Spring中MyBatis应用实践

Mybatis

当一个接口被 @Mapper 标记后,MyBatis 会在启动时自动扫描这个接口,并为其生成一个代理对象。开发者可以通过这个接口直接调用 SQL 语句,而无需自己编写实现类。SQL 语句通常通过 MyBatis 的 XML 配置文件或者在接口方法上使用@Delete@Update@Insert@Select 等注解来指定。

在接口方法上使用注解

1. Delete和Update

将注解和SQL语句放在一个函数上面,在其他地方调用该函数的时候,就可以运行对应的SQL语句。

1
2
3
4
5
6
7
8
//根据ID删除用户  
@Delete("delete from emp where id=#{id}")
public int delete(Integer id);//返回值是影响的记录数



@Update("update emp set username=#{username}, name=#{name}, create_time=#{createTime} where id=#{id}")
public void update(Emp emp);

2. Insert

可以使用@Options注解获取数据库生成的主键值,返回到对象中。

1
2
3
@Options(keyProperty = "id",useGeneratedKeys = true)//将自动生成的主键值赋值给emp对象的id属性  
@Insert("insert into emp(username,name,creat_time) values (#{username},#{name},#{creatTime})")
public void insert(Emp emp);

3. Select

在application.properties中加入下面一行即可打开mybatis驼峰命名自动映射开关。
#开启mybatis驼峰命名自动映射开关 mybatis.configuration.map-underscore-to-camel-case=true

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//Select方式一:开启mybatis驼峰命名自动映射开关  
@Select("select * from emp where id=#{id}")
public Emp getById(Integer id);

//Select方式二:起别名
@Select("select id,username,create_time as createTime from emp where id=#{id}")//AS关键字可以省略
public Emp getById(Integer id);

//Select方式三:@Results,@Result注解手动映射
//property指的是类中的属性名,column指的是表中的字段名
@Select("SELECT id, username, name, create_time FROM emp WHERE id = #{id}")
@Results({
@Result(property = "id", column = "id"),
@Result(property = "username", column = "username"),
@Result(property = "name", column = "name"),
@Result(property = "createTime", column = "create_time")
})
public Emp getById(Integer id);

整体如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
@Mapper
public interface EmpMapper {
//根据ID删除用户
@Delete("delete from emp where id=#{id}")
public int delete(Integer id);//返回值是影响的记录数

@Options(keyProperty = "id",useGeneratedKeys = true)//将自动生成的主键值赋值给emp对象的id属性
@Insert("insert into emp(username,name,creat_time) values (#{username},#{name},#{creatTime})")
public void insert(Emp emp);

@Update("update emp set username=#{username}, name=#{name}, create_time=#{createTime} where id=#{id}")
public void update(Emp emp);

//Select方式一:开启mybatis驼峰命名自动映射开关
@Select("select * from emp where id=#{id}")
public Emp getById(Integer id);

//Select方式二:起别名
@Select("select id,username,create_time AS createTime from emp where id=#{id}")//AS关键字可以省略
public Emp getById(Integer id);

//Select方式三:@Results,@Result注解手动映射
//property指的是类中的属性名,column指的是表中的字段名
@Select("SELECT id, username, name, create_time FROM emp WHERE id = #{id}")
@Results({
@Result(property = "id", column = "id"),
@Result(property = "username", column = "username"),
@Result(property = "name", column = "name"),
@Result(property = "createTime", column = "create_time")
})
public Emp getById(Integer id);


//条件查询员工
@Select("select * from emp where name like '%${name}%' and gender = #{gender} and " +//注意此时如果写#{name}会出现问题
"entrydate between #{begin} and #{end} order by update_time desc ")
public List<Emp> list(String name, Short gender, LocalDate begin, LocalDate end);

@Select("select * from emp where name like concat('%', #{name}, '%') and gender = #{gender} " +//换为concat即可使用
"and entrydate between #{begin} and #{end} order by update_time desc")
public List<Emp> list(String name, Short gender, LocalDate begin, LocalDate end);
}

XML映射文件

XML创建

创建XML文件需要满足以下条件:

• XML映射文件的名称与Mapper接口名称一致,并且将XML映射文件和Mapper接口放置在相同包下(同包同名)。
Pasted image 20240126154515

创建完XML文件,需在前面加入以下约束(https://mybatis.org/mybatis-3/getting-started.html)

1
2
3
4
5
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">

• XML映射文件的namespace属性为Mapper接口全限定名一致。

1
2
3
4
5
6
7
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.XXXXXX.test.mapper.EmpMapper">
<
</mapper>

• XML映射文件中sql语句的id与Mapper 接口中的方法名一致,并保持返回类型一致。

1
2
@Select("select * from emp where name like concat('%', #{name}, '%') and gender = #{gender} and entrydate between #{begin} and #{end} order by update_time desc")
public List<Emp> list(String name, Short gender, LocalDate begin, LocalDate end);
1
2
3
4
5
6
7
8
9
10
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.XXXXX.test.mapper.EmpMapper">
<!-- id为函数名,返回类型为Emp-->
<select id="list" resultType="com.XXXXX.test.pojo.Emp">
select * from emp where name like concat('%', #{name}, '%') and gender = #{gender} and entrydate between #{begin} and #{end} order by update_time desc
</select>
</mapper>

动态SQL

if

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<mapper namespace="com.XXXXX.test.mapper.EmpMapper">
<!-- id为函数名,返回类型为Emp-->
<select id="list" resultType="com.XXXXX.test.pojo.Emp">
select *
from emp
<where>
<if test="name != null">
name like concat('%', #{name}, '%')
</if>
<if test="gender != null">
and gender = #{gender}
</if>
<if test="begin != null and end != null">
and entrydate between #{begin} and #{end}
</if>
order by update_time desc
</where>

</select>
</mapper>

<where>标签内会根据<if>的内容是否成立进行SQL语句的拼接,如name、begin、end都为null,gender不为null,则SQL为select * from emp where gender = #{gender}

foreach

可以通过传递一个List ids,例如:1,3,6,8
将其转换成delete from emp where id in (1,3,6,8)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

<!-- 批量删除员工(18,19,20)-->
<!--
collection: 集合的属性名
item: 集合的元素
separator: 分隔符
open: 前缀,用于开启foreach的SQL片段
close: 后缀,用于结束foreach的SQL片段
-->

<delete id="deleteByIds">
delete from emp where id in
<foreach collection="ids" item="id" separator="," open="(" close=")">
#{id}
</foreach>
</delete>

sql&include

当我们比如说写了很多的select语句select id, username, password, name, gender, image, job, entrydate, dept_id, create_time, update_time from emp ,那么我们可以将它放入sql标签中,在其他地方使用include标签,这样当我们想进行更改的时候,只需要更改一个地方。

1
2
3
4
<sql id="empSelect">
select id, username, password, name, gender, image, job, entrydate, dept_id, create_time, update_time
from emp
</sql>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<select id="list" resultType="com.XXXXX.test.pojo.Emp">
<include refid="empSelect"></include>
<where>
<if test="name != null">
name like concat('%', #{name}, '%')
</if>
<if test="gender != null">
and gender = #{gender}
</if>
<if test="begin != null and end != null">
and entrydate between #{begin} and #{end}
</if>
order by update_time desc
</where>

</select>

当一个接口被 @Mapper 标记后,MyBatis 会在启动时自动扫描这个接口,并为其生成一个代理对象。开发者可以通过这个接口直接调用 SQL 语句,而无需自己编写实现类。SQL 语句通常通过 MyBatis 的 XML 配置文件或者在接口方法上使用@Delete@Update@Insert@Select 等注解来指定。

在接口方法上使用注解

1. Delete和Update

将注解和SQL语句放在一个函数上面,在其他地方调用该函数的时候,就可以运行对应的SQL语句。

1
2
3
4
5
6
7
8
//根据ID删除用户  
@Delete("delete from emp where id=#{id}")
public int delete(Integer id);//返回值是影响的记录数



@Update("update emp set username=#{username}, name=#{name}, create_time=#{createTime} where id=#{id}")
public void update(Emp emp);

2. Insert

可以使用@Options注解获取数据库生成的主键值,返回到对象中。

1
2
3
@Options(keyProperty = "id",useGeneratedKeys = true)//将自动生成的主键值赋值给emp对象的id属性  
@Insert("insert into emp(username,name,creat_time) values (#{username},#{name},#{creatTime})")
public void insert(Emp emp);

3. Select

在application.properties中加入下面一行即可打开mybatis驼峰命名自动映射开关。
#开启mybatis驼峰命名自动映射开关 mybatis.configuration.map-underscore-to-camel-case=true

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//Select方式一:开启mybatis驼峰命名自动映射开关  
@Select("select * from emp where id=#{id}")
public Emp getById(Integer id);

//Select方式二:起别名
@Select("select id,username,create_time as createTime from emp where id=#{id}")//AS关键字可以省略
public Emp getById(Integer id);

//Select方式三:@Results,@Result注解手动映射
//property指的是类中的属性名,column指的是表中的字段名
@Select("SELECT id, username, name, create_time FROM emp WHERE id = #{id}")
@Results({
@Result(property = "id", column = "id"),
@Result(property = "username", column = "username"),
@Result(property = "name", column = "name"),
@Result(property = "createTime", column = "create_time")
})
public Emp getById(Integer id);

整体如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
@Mapper
public interface EmpMapper {
//根据ID删除用户
@Delete("delete from emp where id=#{id}")
public int delete(Integer id);//返回值是影响的记录数

@Options(keyProperty = "id",useGeneratedKeys = true)//将自动生成的主键值赋值给emp对象的id属性
@Insert("insert into emp(username,name,creat_time) values (#{username},#{name},#{creatTime})")
public void insert(Emp emp);

@Update("update emp set username=#{username}, name=#{name}, create_time=#{createTime} where id=#{id}")
public void update(Emp emp);

//Select方式一:开启mybatis驼峰命名自动映射开关
@Select("select * from emp where id=#{id}")
public Emp getById(Integer id);

//Select方式二:起别名
@Select("select id,username,create_time AS createTime from emp where id=#{id}")//AS关键字可以省略
public Emp getById(Integer id);

//Select方式三:@Results,@Result注解手动映射
//property指的是类中的属性名,column指的是表中的字段名
@Select("SELECT id, username, name, create_time FROM emp WHERE id = #{id}")
@Results({
@Result(property = "id", column = "id"),
@Result(property = "username", column = "username"),
@Result(property = "name", column = "name"),
@Result(property = "createTime", column = "create_time")
})
public Emp getById(Integer id);


//条件查询员工
@Select("select * from emp where name like '%${name}%' and gender = #{gender} and " +//注意此时如果写#{name}会出现问题
"entrydate between #{begin} and #{end} order by update_time desc ")
public List<Emp> list(String name, Short gender, LocalDate begin, LocalDate end);

@Select("select * from emp where name like concat('%', #{name}, '%') and gender = #{gender} " +//换为concat即可使用
"and entrydate between #{begin} and #{end} order by update_time desc")
public List<Emp> list(String name, Short gender, LocalDate begin, LocalDate end);
}

XML映射文件

XML创建

创建XML文件需要满足以下条件:

• XML映射文件的名称与Mapper接口名称一致,并且将XML映射文件和Mapper接口放置在相同包下(同包同名)。
![[Pasted image 20240126154515.png]]

创建完XML文件,需在前面加入以下约束(https://mybatis.org/mybatis-3/getting-started.html)

1
2
3
4
5
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">

• XML映射文件的namespace属性为Mapper接口全限定名一致。

1
2
3
4
5
6
7
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.XXXXXX.test.mapper.EmpMapper">
<
</mapper>

• XML映射文件中sql语句的id与Mapper 接口中的方法名一致,并保持返回类型一致。

1
2
@Select("select * from emp where name like concat('%', #{name}, '%') and gender = #{gender} and entrydate between #{begin} and #{end} order by update_time desc")
public List<Emp> list(String name, Short gender, LocalDate begin, LocalDate end);
1
2
3
4
5
6
7
8
9
10
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.XXXXX.test.mapper.EmpMapper">
<!-- id为函数名,返回类型为Emp-->
<select id="list" resultType="com.XXXXX.test.pojo.Emp">
select * from emp where name like concat('%', #{name}, '%') and gender = #{gender} and entrydate between #{begin} and #{end} order by update_time desc
</select>
</mapper>

动态SQL

if

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<mapper namespace="com.XXXXX.test.mapper.EmpMapper">
<!-- id为函数名,返回类型为Emp-->
<select id="list" resultType="com.XXXXX.test.pojo.Emp">
select *
from emp
<where>
<if test="name != null">
name like concat('%', #{name}, '%')
</if>
<if test="gender != null">
and gender = #{gender}
</if>
<if test="begin != null and end != null">
and entrydate between #{begin} and #{end}
</if>
order by update_time desc
</where>

</select>
</mapper>

<where>标签内会根据<if>的内容是否成立进行SQL语句的拼接,如name、begin、end都为null,gender不为null,则SQL为select * from emp where gender = #{gender}

foreach

可以通过传递一个List ids,例如:1,3,6,8
将其转换成delete from emp where id in (1,3,6,8)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

<!-- 批量删除员工(18,19,20)-->
<!--
collection: 集合的属性名
item: 集合的元素
separator: 分隔符
open: 前缀,用于开启foreach的SQL片段
close: 后缀,用于结束foreach的SQL片段
-->

<delete id="deleteByIds">
delete from emp where id in
<foreach collection="ids" item="id" separator="," open="(" close=")">
#{id}
</foreach>
</delete>

sql&include

当我们比如说写了很多的select语句select id, username, password, name, gender, image, job, entrydate, dept_id, create_time, update_time from emp ,那么我们可以将它放入sql标签中,在其他地方使用include标签,这样当我们想进行更改的时候,只需要更改一个地方。

1
2
3
4
<sql id="empSelect">
select id, username, password, name, gender, image, job, entrydate, dept_id, create_time, update_time
from emp
</sql>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<select id="list" resultType="com.XXXXX.test.pojo.Emp">
<include refid="empSelect"></include>
<where>
<if test="name != null">
name like concat('%', #{name}, '%')
</if>
<if test="gender != null">
and gender = #{gender}
</if>
<if test="begin != null and end != null">
and entrydate between #{begin} and #{end}
</if>
order by update_time desc
</where>

</select>