Mybaits
Mybatis与JDBC的对比
快速入门
有些步骤的代码就是从这copy的
https://mybatis.org/mybatis-3/zh/getting-started.html
1.创建user表
DROP TABLE IF EXISTS `tb_user`;
CREATE TABLE `tb_user` (
`id` int NOT NULL,
`username` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL,
`password` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL,
`gender` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL,
`addr` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of user
-- ----------------------------
INSERT INTO `tb_user` VALUES (1, 'admin', '123456', '男', '北京');
INSERT INTO `tb_user` VALUES (2, 'Benson', '666666', '男', '广东');
INSERT INTO `tb_user` VALUES (3, 'Lucy', '888888', '女', '上海');
SET FOREIGN_KEY_CHECKS = 1;
2.导入maven依赖
<dependencies>
<dependency><!--mysql依赖-->
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.28</version>
</dependency>
<dependency><!--mybatis依赖-->
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.3</version>
</dependency>
<dependency><!--单元测试-->
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.20</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>1.2.3</version>
</dependency>
</dependencies>
将logback.xml粘贴到main的resources
<?xml version="1.0" encoding="UTF-8"?>
<!-- 配置文件修改时重新加载,默认true -->
<configuration scan="true">
<!--定义日志文件的存储地址 勿在 LogBack 的配置中使用相对路径-->
<property name="CATALINA_BASE" value="**/logs"></property>
<!-- 控制台输出 -->
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder charset="UTF-8">
<!-- 输出日志记录格式 -->
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<!-- 第一个文件输出,每天产生一个文件 -->
<appender name="FILE1" class="ch.qos.logback.core.rolling.RollingFileAppender">
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 输出文件路径+文件名 -->
<fileNamePattern>${CATALINA_BASE}/aa.%d{yyyyMMdd}.log</fileNamePattern>
<!-- 保存30天的日志 -->
<maxHistory>30</maxHistory>
</rollingPolicy>
<encoder charset="UTF-8">
<!-- 输出日志记录格式 -->
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<!-- 第二个文件输出,每天产生一个文件 -->
<appender name="FILE2" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${CATALINA_BASE}/bb.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${CATALINA_BASE}/bb.%d{yyyyMMdd}.log</fileNamePattern>
<maxHistory>30</maxHistory>
</rollingPolicy>
<encoder charset="UTF-8">
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<appender name="CUSTOM" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${CATALINA_BASE}/custom.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- daily rollover -->
<fileNamePattern>${CATALINA_BASE}/custom.%d{yyyy-MM-dd}.log</fileNamePattern>
<!-- keep 30 days' worth of history -->
<maxHistory>30</maxHistory>
</rollingPolicy>
<encoder charset="UTF-8">
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<!-- 设置日志输出级别 -->
<root level="ERROR">
<appender-ref ref="CONSOLE" />
</root>
<logger name="file1" level="DEBUG">
<appender-ref ref="FILE1" />
</logger>
<logger name="file1" level="INFO">
<appender-ref ref="FILE2" />
</logger>
<!-- 自定义logger -->
<logger name="custom" level="INFO">
<appender-ref ref="CUSTOM" />
</logger>
</configuration>
编写mybatis核心配置文件
在main的resources下新建mybatis-config.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<!--数据库连接信息-->
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql:///test"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</dataSource>
</environment>
</environments>
<mappers><!--加载sql映射文件路径-->
<mapper resource="UserMapper.xml"/>
</mappers>
</configuration>
新建pojo包下的User类
package com.benson.pojo;
public class User {
private Integer id;
private String username;
private String password;
private String gender;
private String addr;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
public String getAddr() {
return addr;
}
public void setAddr(String addr) {
this.addr = addr;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", password='" + password + '\'' +
", gender='" + gender + '\'' +
", addr='" + addr + '\'' +
'}';
}
}
编码sql映射文件
统一管理sql语句
在main的resources新建对应sql映射的配置文件
UserMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--namespace:名称空间,相当于包,用来区分同名id的-->
<mapper namespace="test">
<select id="selectAll" resultType="com.benson.pojo.User">
<!--id是指向sql的唯一标识,resultType是返回结果的类型-->
select * from tb_user;
</select>
</mapper>
编码
在pojo包同级新建测试类MybatisDemo.java
package com.benson;
import com.benson.pojo.User;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
public class MybatisDemo {
public static void main(String[] args) throws IOException {
//1.加载Mybatis核心配置文件,获取SqlSessionFactory对象
String resource = "mybatis-config.xml";//核心配置文件路径
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//2.获取SqlSession对象,它能执行sql语句
SqlSession sqlSession = sqlSessionFactory.openSession();
//3.执行sql
List<User> users = sqlSession.selectList("test.selectAll");
//根据UserMapper的test名称空间的idselectAll来执行对应的语句
System.out.println(users);
//4.释放资源
sqlSession.close();
}
}
总结
Mybatis就是把数据库的连接信息和sql语句分别写到mybatis-config.xml、UserMapper.xml配置文件中,将共性提取出来到配置中,java类里如MybatisDemo.java写的都是基本不变的业务逻辑。
后期维护时一些信息如数据库密码、sql语句要改变,就到配置中改,不需要动业务逻辑。
Mapper代理开发
sqlSession的方法还存在硬编码的问题,selectList方法的参数是写死的
用Mapper代理就能解决这个问题
Mapper代理开发的规则
创建Mapper接口
新建mapper包并新建Mapper接口
然后在resources下新建目录,名字不能用.而是/来分隔,这样才有层次结构
注意名字要相同,然后把UserMapper.xml移动到该包里面去,同时改下mybatis-config.xml中UserMapper的路径
配置sql映射文件
设置SQL映射文件的namespace属性为Mapper接口全限定名
以前是随便写的,现在要改成对应的目录了
Mapper接口定义方法
在Mapper接口中定义方法,方法名就是SQL映射文件中sql语句的id,并保持参数类型和返回值类型一致
编码
MybatisDemo.java
package com.benson;
import com.benson.mapper.UserMapper;
import com.benson.pojo.User;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
public class MybatisDemo {
public static void main(String[] args) throws IOException {
//1.加载Mybatis核心配置文件,获取SqlSessionFactory对象
String resource = "mybatis-config.xml";//核心配置文件路径
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//2.获取SqlSession对象,它能执行sql语句
SqlSession sqlSession = sqlSessionFactory.openSession();
//3.获取UserMapper接口的代理对象
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
List<User> users = userMapper.selectAll();
System.out.println(users);
//4.释放资源
sqlSession.close();
}
}
拓展
如果Mapper接口名称和sql文件名称相同
并在同一目录下,编译后可视作在同一目录下
就能简化mybatis-config.xml中加载sql映射文件的语句
当有很多sql映射文件(如StudentMapper、TeacherMapper)时就不用一句句地写
直接通过扫描包来加载
简单来说,只要按照上述的3个规范进行Mapper代理开发,都能用这种方式加载。
Mybatis核心配置文件
environments
该标签下可以用多个environment标签(id来区分),用来配置多个数据库信息,通过default切换当前数据库
如图开发和生产采用两个数据库,让当前数据库切换为开发时用的数据库(id为test)
当然开发库那里应该和生产库信息不一样,图中是因为教学举例而没改
transactionManager
事务的管理方式,下图采用的是jdbc的方式
不过无需深入mybatis的事务管理,后面开发会用Spring接管事务
dataSource
用来管理数据库连接的
mappers
映射器
typeAliases
类型别名,用来降低配置文件中参数的冗余度
在mybatis-config.xml中加入这段语句,在类型别名标签中扫描itheima.pojo这个包
相当于给pojo包下的所有实体类起了别名,别名默认是User且不区分大小写
所以可以在对应sql映射文件UserMapper.xml中简化名称的书写
标签顺序
一定要按照如图的顺序编写便签,如mappers在同级中一定要放在最后
typeAliases在mappers后面就报错了
使用Mybatis实现增删改查
有两种方式:配置文件&注解
先以配置文件为例
准备环境
1.创建tb_brand表
create table tb_brand(
id int primary key auto_increment,
brand_name varchar(20),
company_name varchar(20),
ordered int,
description varchar(100),
status int
);
insert into tb_brand(
brand_name, company_name, ordered, description, status)
values ('华为','华为公司',1,'中华有为',1),
('小米','小米公司',2,'areyouok',1),
('vivo','vivo公司',3,'中华有为',1);
select * from tb_brand;
2.Brand.java
package com.benson.pojo;
public class Brand {
private Integer id;
private String brandName;
private String companyName;
private Integer ordered;
private String description;
private Integer status;//0:禁用 1:启用
/*基本类型建议换成包装类,因为基本类型的默认值可能不适应需求
比如int的默认值是0,对于ordered和status而言不适合
而Integer的默认值是null,相比之下更合适些
*/
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getBrandName() {
return brandName;
}
public void setBrandName(String brandName) {
this.brandName = brandName;
}
public String getCompanyName() {
return companyName;
}
public void setCompanyName(String companyName) {
this.companyName = companyName;
}
public Integer getOrdered() {
return ordered;
}
public void setOrdered(Integer ordered) {
this.ordered = ordered;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public Integer getStatus() {
return status;
}
public void setStatus(Integer status) {
this.status = status;
}
@Override
public String toString() {
return "Brand{" +
"id=" + id +
", brandName='" + brandName + '\'' +
", companyName='" + companyName + '\'' +
", ordered=" + ordered +
", description='" + description + '\'' +
", status=" + status +
'}';
}
}
3.MybatisX插件
能够快速在Mapper配置的sql和对应接口的方法之间跳转,加快找代码的效率
查询
查询所有
mybatis-config.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<!--数据库连接信息-->
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql:///test"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</dataSource>
</environment>
</environments>
<mappers><!--加载sql映射文件路径-->
<mapper resource="com\benson\mapper\BrandMapper.xml"/>
</mappers>
</configuration>
BrandMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--namespace:名称空间,相当于包,用来区分同名id的-->
<mapper namespace="com.benson.mapper.BrandMapper">
<select id="selectAll" resultType="com.benson.pojo.Brand">
<!--id是指向sql的唯一标识,resultType是返回结果的类型-->
select * from tb_brand;
</select>
</mapper>
Test.java
package com.benson;
import com.benson.mapper.BrandMapper;
import com.benson.pojo.Brand;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
public class Test {
public static void main(String[] args) throws IOException {
//1.加载Mybatis核心配置文件,获取SqlSessionFactory对象
String resource = "mybatis-config.xml";//核心配置文件路径
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//2.获取SqlSession对象,它能执行sql语句
SqlSession sqlSession = sqlSessionFactory.openSession();
//3.获取UserMapper接口的代理对象
BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);
//4.执行方法
List<Brand> brands = brandMapper.selectAll();
System.out.println(brands);
//4.释放资源
sqlSession.close();
}
}
商品名和公司名都是null,因为Brand定义的属性brandName和数据库字段brand_name不一致
- 1.把Brand实体类属性改成跟数据库一样,brand_name。但不适合项目开发,因为前后端很可能不是同一个人写的
- 2.sql语句起别名
但这样做每个查询的sql都要起一次别名很麻烦,所以可以用sql片段来提取要查询的字段,用到再导入
但如果查询的字段有所改变又要写一个sql片段,这种方法也不够简便
resultMap
BrandMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.benson.mapper.BrandMapper">
<!--id随便写,type是和哪个类映射-->
<resultMap id="brandResultMap" type="com.benson.pojo.Brand">
<result column="brand_name" property="brandName" />
<!--
id标签是对主键字段作映射的,result标签是映射普通字段的
这里要映射的都是普通字段,所以用result标签
让数据库的字段名和实体类的属性名作映射,一一对应-->
<result column="company_name" property="companyName" />
</resultMap>
<select id="selectAll" resultMap="brandResultMap">
<!--id是指向sql的唯一标识,resultType是返回结果的类型-->
<!--resultMap替换掉resultType-->
select * from tb_brand;
</select>
</mapper>
条件查询
单条件查询
特殊字符处理
多条件查询
BrandMapper.xml
BrandMapper.java
Test.java
动态条件查询
用户查询时不一定会把所有条件都输入,更多是输入一个条件,比如只输入商品名,这时也要返回符合的结果。
多条件查询是用and连接条件的,所以条件不输全就得不到结果。要解决这种需求,就要用到动态条件查询。
用if判断用户是否在对应的条件填写了信息
mybatis提供了更好的方法
单条件动态查询
Test.java
BrandMapper.xml
不写otherwise,用where标签包裹更简便,where标签十分灵活,同样能解决条件为空时不报错
条件值为空时,where标签会把where关键字也去掉
添加
但仅仅这样无法添加成功,因为mybatis默认是手动提交事务的,代码里没有写提交事务。
有两种方式
再执行一次
主键返回
添加成功后是获取不到主键id的值的
修改
修改全部
修改动态字段
修改部分字段时,比如修改密码,只会修改密码字段的值,就用到动态sql了
删除
根据id删除
批量删除
如果嫌in括号一上一下不好看,可以用标签来美化
open和close分别是foreach标签开头和结尾的位置
单例测试
maven项目有main和test两个大的目录,一个是放生产环境源码的,一个是开发时用来测试的
开发时的测试类可以写在test的java目录下
同时测试类里可以使用@Test来使方法单独使用,不需要在psvm中调用来使用方法
目的是方便测试不同的方法,开发中往往会写很多个方法,在psvm中调用又比较麻烦
就可以用@Test
每个绿色按钮对应各自的方法
参数传递
参数类型是Collection、List、Array和多个参数,mybatis会封装成Map集合
共同点是会根据参数的先后用arg0、arg1、arg2这样的顺序标记对应的参数,值都是对应的数据
不同点是会额外根据参数的类型用对应类型的键作标记
-
多个参数
如在接口中的方法List<Brand> select(String username,String password)
username对应的key的arg0,password对应的key的arg1
多个参数额外的key是param,所以username还有一个key,param1。password还有一个key,param2。
在sql映射中可以用key来表示username和password的参数占位符
-
Array
如void deleteByIds(int[] ids);
参数类型为数组,对应的key有arg0和array,所以能用#{arg0}或者#{array}来传参
其他两种类型同理
总结
对于方法中参数类型是Collection、List、Array和有多个参数的情况,通通使用@Param注解
因为能大大提高代码的可阅读性
如
源码
Brand.java
package com.benson.pojo;
public class Brand {
private Integer id;
private String brandName;
private String companyName;
private Integer ordered;
private String description;
private Integer status;//0:禁用 1:启用
/*基本类型建议换成包装类,因为基本类型的默认值可能不适应需求
比如int的默认值是0,对于ordered和status而言不适合
而Integer的默认值是null,相比之下更合适些
*/
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getBrandName() {
return brandName;
}
public void setBrandName(String brandName) {
this.brandName = brandName;
}
public String getCompanyName() {
return companyName;
}
public void setCompanyName(String companyName) {
this.companyName = companyName;
}
public Integer getOrdered() {
return ordered;
}
public void setOrdered(Integer ordered) {
this.ordered = ordered;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public Integer getStatus() {
return status;
}
public void setStatus(Integer status) {
this.status = status;
}
@Override
public String toString() {
return "Brand{" +
"id=" + id +
", brandName='" + brandName + '\'' +
", companyName='" + companyName + '\'' +
", ordered=" + ordered +
", description='" + description + '\'' +
", status=" + status +
'}';
}
}
mybatis-config.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<!--数据库连接信息-->
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql:///test"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</dataSource>
</environment>
</environments>
<mappers><!--加载sql映射文件路径-->
<mapper resource="com\benson\mapper\BrandMapper.xml"/>
</mappers>
</configuration>
BrandMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.benson.mapper.BrandMapper">
<!--id随便写,type是和哪个类映射-->
<resultMap id="brandResultMap" type="com.benson.pojo.Brand">
<result column="brand_name" property="brandName"/>
<!--
id标签是对主键字段作映射的,result标签是映射普通字段的
这里要映射的都是普通字段,所以用result标签
让数据库的字段名和实体类的属性名作映射,一一对应-->
<result column="company_name" property="companyName"/>
</resultMap>
<!--查询所有-->
<select id="selectAll" resultMap="brandResultMap">
<!--id是指向sql的唯一标识,resultType是返回结果的类型-->
<!--resultMap替换掉resultType-->
select * from tb_brand;
</select>
<!--单条件查询-->
<select id="selectById" resultMap="brandResultMap">
select * from tb_brand where id = #{id};
<!--#{id}是selectById(id)传过来的参数id
还有${id}这种写法,不过这种写法存在sql注入的风险,适用于列明不固定的时候
而#{id}能加参数id替换为?规避sql注入
-->
</select>
<!--多条件查询-->
<select id="selectByCondition" resultMap="brandResultMap">
select * from tb_brand
where status = #{status}
and company_name like #{companyName}<!--模糊查询-->
and brand_name like #{brandName};
</select>
<!--动态条件查询-->
<select id="selectByConditionDynamic" resultMap="brandResultMap">
select * from tb_brand
<where>
<if test="status != null"><!--如果条件status不为空就赋值-->
status = #{status}
</if>
<if test="companyName != null and companyName != ''"><!--不为空且不为空字符串-->
and company_name like #{companyName}<!--模糊查询-->
</if>
<if test="brandName != null and brandName != ''"><!--不为空且不为空字符串-->
and brand_Name like #{brandName}
</if>
</where>
</select>
<!--单条件动态查询-->
<select id="selectByConditionSingle" resultMap="brandResultMap">
select * from tb_brand
<where>
<choose><!--相当于switch-->
<when test="status != null"><!--相当于case-->
status = #{status}
</when>
<when test="companyName != null and companyName != ''">
company_name like #{companyName}
</when>
<when test="brandName != null and brandName != ''">
brand_Name like #{brandName}
</when>
</choose>
</where>
</select>
<!--添加-->
<insert id="add" useGeneratedKeys="true" keyProperty="id">
<!--
useGeneratedKeys="true"返回自增主键id
keyProperty="id"接收主键id的值-->
insert into tb_brand(brand_name,company_name,ordered,description,status)
values(#{brandName},#{companyName},#{ordered},#{description},#{status});
</insert>
<!--修改全部-->
<update id="updateAll">
update tb_brand
set
brand_name = #{brandName},
company_name = #{companyName},
ordered = #{ordered},
description = #{description},
status = #{status}
where id = #{id};
</update>
<!--修改动态字段-->
<update id="updateDynamic">
update tb_brand
<set><!--跟where标签类似,解决无数据和最后一个数据有逗号的sql语法报错-->
<if test="brandName != null and brandName != ''">
brand_name = #{brandName},
</if>
<if test="companyName != null and companyName != ''">
company_name = #{companyName},
</if>
<if test="ordered != null">
ordered = #{ordered},
</if>
<if test="description != null and description != ''">
description = #{description},
</if>
<if test="status != null">
status = #{status}
</if>
</set>
where id = #{id};
</update>
<!--根据id删除-->
<delete id="deleteById">
delete from tb_brand where id = #{id};
</delete>
<!--批量删除-->
<delete id="deleteByIds">
delete from tb_brand where id
in(
<!--用foreach来遍历出ids数组的元素item,名为id
collection="ids"指明ids就是要遍历的数组
这里如果接口那不用注解标明,是不能写ids的!!!而是array
因为mybatis默认会将数据参数封装为一个Map集合,key是array,值是数组参数的值
而使用注解能改变map集合的默认key名称
separator是分隔符,用,来分隔每个item,保证sql的语法正确
而且-->
<foreach collection="ids" item="id" separator=",">
#{id}
</foreach>
);
</delete>
</mapper>
BrandMapper.java
package com.benson.mapper;
import com.benson.pojo.Brand;
import org.apache.ibatis.annotations.Param;
import java.util.List;
import java.util.Map;
public interface BrandMapper {
List<Brand> selectAll();
Brand selectById(int id);
/*
* 多条件查询 有3种接收参数的方式
* 1.散装参数 用注解接收 @Param("sql映射对应的参数占位符名称")
* @Param("status")的status对应sql映射中status = #{status}的#{status}中的status
* 2.对象参数:对象的属性名要和参数占位符名称一致
* 3.集合参数
* */
//1.散装参数
// List<Brand> selectByCondition(@Param("status") int status,
// @Param("companyName") String companyName,
// @Param("brandName")String brandName);
//2.对象参数
// List<Brand> selectByCondition(Brand brand);
//3.集合参数
List<Brand> selectByCondition(Map map);
//动态条件查询
List<Brand> selectByConditionDynamic(Map map);
//单条件动态查询
List<Brand> selectByConditionSingle(Brand brand);
//添加
void add(Brand brand);
//修改全部
void updateAll(Brand brand);
//修改动态字段
void updateDynamic(Brand brand);
//根据id删除
void deleteById(int id);
//批量删除
void deleteByIds(@Param("ids") int[] ids);
}
测试类
Test.java
package com.benson;
import com.benson.mapper.BrandMapper;
import com.benson.pojo.Brand;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class Test {
public static void main(String[] args) throws IOException {
//1.加载Mybatis核心配置文件,获取SqlSessionFactory对象
String resource = "mybatis-config.xml";//核心配置文件路径
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//2.获取SqlSession对象,它能执行sql语句
SqlSession sqlSession = sqlSessionFactory.openSession(true);
//3.获取UserMapper接口的代理对象
BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);
//4.执行方法
//查询所有
// List<Brand> brands = brandMapper.selectAll();
// System.out.println(brands);
//单条件查询
// int id = 2;//模拟前端单条件查询的数据
// Brand brand = brandMapper.selectById(id);
// System.out.println(brand);
//多条件查询&单条件动态查询
// int status = 1;
// String companyName = "华为";
// String brandName = "华为";//模拟前端多条件查询的数据
// //模糊处理数据
// companyName = "%" + companyName + "%";
// brandName = "%" + brandName + "%";
//2.封装对象&单条件动态查询
// Brand brand = new Brand();
//// brand.setStatus(status);
// brand.setCompanyName(companyName);
// brand.setBrandName(brandName);
//3.集合参数
// Map map = new HashMap();
//// map.put("status",status);
// map.put("companyName",companyName);
//// map.put("brandName",brandName);
// List<Brand> brands = brandMapper.selectByCondition(status, companyName, brandName);//1.散装参数
// List<Brand> brands = brandMapper.selectByCondition(brand);//2.对象参数
// List<Brand> brands = brandMapper.selectByCondition(map);//3.集合参数
// List<Brand> brands = brandMapper.selectByConditionDynamic(map);//动态条件查询
//单条件动态查询
// List<Brand> brands = brandMapper.selectByConditionSingle(brand);
// System.out.println(brands);
//添加
// int status = 1;
// String companyName = "oppo";
// String brandName = "oppo公司";
// String description = "前后两千万";
// int ordered = 5;
//
// Brand brand = new Brand();
// brand.setStatus(status);
// brand.setCompanyName(companyName);
// brand.setBrandName(brandName);
// brand.setDescription(description);
// brand.setOrdered(ordered);
//
// brandMapper.add(brand);
// System.out.println(brand.getId());
//修改所有
// int status = 0;
// String companyName = "oppo";
// String brandName = "oppo公司";
// String description = "oppo前后像素两千万";
// int ordered = 15;
// int id = 12;
//
// Brand brand = new Brand();
// brand.setStatus(status);
//// brand.setCompanyName(companyName);
//// brand.setBrandName(brandName);
// brand.setDescription(description);
//// brand.setOrdered(ordered);
// brand.setId(id);
//
//// brandMapper.updateAll(brand);
//
// //修改动态字段
// brandMapper.updateDynamic(brand);
// //根据id删除
// int id = 13;
// brandMapper.deleteById(id);
//4.释放资源
sqlSession.close();
}
}
MybatisTest.java
import com.benson.mapper.BrandMapper;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Test;
import java.io.IOException;
import java.io.InputStream;
public class MybatisTest {
@Test
public void testDeleteByIds() throws IOException{
//1.加载Mybatis核心配置文件,获取SqlSessionFactory对象
String resource = "mybatis-config.xml";//核心配置文件路径
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//2.获取SqlSession对象,它能执行sql语句
SqlSession sqlSession = sqlSessionFactory.openSession(true);
//3.获取UserMapper接口的代理对象
BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);
//4.执行方法
int[] ids = {12,14,15};//模拟要删除的几个商品
brandMapper.deleteByIds(ids);
//5.释放资源
sqlSession.close();
}
}
注解开发
跟配置文件开发的区别在于,配置文件开发是把sql写在配置文件里
注解开发是把sql写在注解里
使用注解来映射简单语句会使代码显得更加简洁,但对于稍微复杂一点的语句,Java注解不仅力不从心,还会让你本就复杂的sql语句更加混乱不堪。因此,简单的sql用注解,复杂的用xml。
- 示例
把xml相关的语句注释掉,然后在BrandMapper.java接口中
在方法的上面一行用@Select注解写sql