一、简介
上篇文章,我们介绍了Mybatis常用的关系映射,本文将在上篇文章项目的基础上,总计一下Mybatis中动态SQL的常用用法,项目结构可以从这里https://gitee.com/weixiaohuai/springboot-mybatis.git下载。相信大家没用Mybatis之前,都碰到过各种条件判断拼接SQL、需要去掉多余的逗号等痛苦,Mybatis中的动态SQL能很好的解决上面说的情况,可以很灵活的组装SQL语句,从而提高开发效率。
二、动态SQL
Mybatis动态SQL提高了很多标签,如if、choose、where 、set、trim、foreach、sql等,下面我们逐个讲解每一个标签的用法:
【a】if标签
判断语句,通常用于满足某个条件就拼接上某种过滤条件等场景。
(1) mapper接口:
/**
* if
*/
List<Map<String, Object>> testIf(@Param("sid") Integer sid, @Param("sname") String sname);
(2) mapper映射文件:
<!--if-->
<select id="testIf" resultType="java.util.Map">
select *
from tbl_student t
where 1 = 1
<if test="sid != null and sid != ''">
and t.s_id = #{sid}
</if>
<if test="sname != null and sname != ''">
and t.s_name = #{sname}
</if>
</select>
(3) 测试用例:
@Test
public void testIf() {
List<Map<String, Object>> list1 = studentMapper.testIf(null, "学生5");
for (Map<String, Object> map : list1) {
System.out.println(map);
}
List<Map<String, Object>> list2 = studentMapper.testIf(1, "");
for (Map<String, Object> map : list2) {
System.out.println(map);
}
List<Map<String, Object>> list3 = studentMapper.testIf(2, "学生2");
for (Map<String, Object> map : list3) {
System.out.println(map);
}
}
(4) 测试结果:
【b】choose标签
功能类似if,其中包含when/otherwise子标签。
(1) mapper接口:
/**
* choose
*/
List<Map<String, Object>> testChoose(@Param("sid") Integer sid, @Param("sname") String sname);
(2) mapper映射文件:
<!--choose(when/otherwise)-->
<select id="testChoose" resultType="java.util.Map">
select *
from tbl_student t
where 1 = 1
<choose>
<when test="sid != null and sid != ''">
and t.s_id = #{sid}
</when>
<when test="sname != null and sname != ''">
and t.s_name = #{sname}
</when>
<otherwise>
and t.s_id in (1,2)
</otherwise>
</choose>
</select>
(3) 测试用例:
@Test
public void testChoose() {
List<Map<String, Object>> list1 = studentMapper.testChoose(null, "学生5");
for (Map<String, Object> map : list1) {
System.out.println(map);
}
List<Map<String, Object>> list2 = studentMapper.testChoose(1, "");
for (Map<String, Object> map : list2) {
System.out.println(map);
}
List<Map<String, Object>> list3 = studentMapper.testChoose(2, "学生2");
for (Map<String, Object> map : list3) {
System.out.println(map);
}
List<Map<String, Object>> list4 = studentMapper.testChoose(null, null);
for (Map<String, Object> map : list4) {
System.out.println(map);
}
}
(4) 测试结果:
【c】where标签
(1) mapper接口:
/**
* where
*/
List<Map<String, Object>> testWhere01(@Param("sid") Integer sid, @Param("sname") String sname);
List<Map<String, Object>> testWhere02(@Param("sid") Integer sid, @Param("sname") String sname);
(2) mapper映射文件:
<select id="testWhere01" resultType="map">
/*假设只有第二个条件满足,此时sql: select * from tbl_student t where and t.s_name = 'xxx' 明显不正确
此时,可以使用where标签来帮助我们去掉多余的and
*/
select *
from tbl_student t
where
<if test="sid != null and sid != ''">
t.s_id = #{sid}
</if>
<if test="sname != null and sname != ''">
and t.s_name = #{sname}
</if>
</select>
<!--where-->
<select id="testWhere02" resultType="map">
select *
from tbl_student t
<where>
<if test="sid != null and sid != ''">
and t.s_id = #{sid}
</if>
<if test="sname != null and sname != ''">
and t.s_name = #{sname}
</if>
</where>
</select>
(3) 测试用例:
@Test
public void testWhere01() {
List<Map<String, Object>> list1 = studentMapper.testWhere01(null, "学生5");
for (Map<String, Object> map : list1) {
System.out.println(map);
}
}
@Test
public void testWhere02() {
List<Map<String, Object>> list1 = studentMapper.testWhere02(null, "学生5");
for (Map<String, Object> map : list1) {
System.out.println(map);
}
List<Map<String, Object>> list2 = studentMapper.testWhere02(1, "");
for (Map<String, Object> map : list2) {
System.out.println(map);
}
List<Map<String, Object>> list3 = studentMapper.testWhere02(2, "学生2");
for (Map<String, Object> map : list3) {
System.out.println(map);
}
List<Map<String, Object>> list4 = studentMapper.testWhere02(null, null);
for (Map<String, Object> map : list4) {
System.out.println(map);
}
}
(4) 测试结果:
【d】set标签
可以自动去除sql中的多余的逗号‘,’
(1) mapper接口:
/**
* set
*/
Integer testSet(@Param("sid") Integer sid, @Param("sname") String sname);
(2) mapper映射文件:
<!--set-->
<!--
set标签: 可以自动去除sql中的多余的逗号‘,’
-->
<update id="testSet">
update tbl_student t
/*此时执行的sql为: update tbl_student t SET s_name = ? WHERE s_id = ? */
<set>
<if test="sname != null and sname != ''">
s_name = #{sname},
</if>
</set>
<where>
s_id = #{sid}
</where>
</update>
(3) 测试用例:
@Test
public void testSet() {
studentMapper.testSet(1, "zhangsan");
List<Map<String, Object>> list = studentMapper.testWhere01(1, null);
for (Map<String, Object> map : list) {
System.out.println(map);
}
}
(4) 测试结果:
【e】trim标签
trim标签: 一般用于去除sql语句中多余的and关键字,逗号,或者给sql语句前拼接 “where“、“set“以及“values(“ 等前缀,或者添加“)“等后缀.
prefix: 给sql语句拼接的前缀
prefixOverrides: 去除sql语句前面的关键字或者字符,假设该属性指定为”AND”,当sql语句的开头为”AND”,trim标签将会去除该”AND”
suffix: 给sql语句拼接的后缀
suffixOverrides: 去除sql语句后面的关键字或者字符
(1) mapper接口:
/**
* 使用trim实现where同样功能
*/
List<Map<String, Object>> testTrimWhere(@Param("sid") Integer sid, @Param("sname") String sname);
/**
* 使用trim实现set同样功能
*/
Integer testSetTrim(@Param("sid") Integer sid, @Param("sname") String sname);
(2) mapper映射文件:
<!--使用trim实现where等价的功能-->
<select id="testTrimWhere" resultType="map">
select *
from tbl_student t
/*
trim标签: 一般用于去除sql语句中多余的and关键字,逗号,或者给sql语句前拼接 “where“、“set“以及“values(“ 等前缀,或者添加“)“等后缀
prefix: 给sql语句拼接的前缀
prefixOverrides: 去除sql语句前面的关键字或者字符,假设该属性指定为”AND”,当sql语句的开头为”AND”,trim标签将会去除该”AND”
suffix: 给sql语句拼接的后缀
suffixOverrides: 去除sql语句后面的关键字或者字符
*/
<trim prefix="where" prefixOverrides="and | or">
<if test="sid != null and sid != ''">
and t.s_id = #{sid}
</if>
<if test="sname != null and sname != ''">
and t.s_name = #{sname}
</if>
</trim>
</select>
<!--使用trim实现set同样的功能-->
<update id="testSetTrim">
update tbl_student t
<trim prefixOverrides="," prefix="set" suffixOverrides=",">
<if test="sname != null and sname != ''">
,s_name = #{sname},
</if>
</trim>
<where>
s_id = #{sid}
</where>
</update>
(3) 测试用例:
@Test
public void testTrimWhere() {
List<Map<String, Object>> list1 = studentMapper.testTrimWhere(null, "学生5");
for (Map<String, Object> map : list1) {
System.out.println(map);
}
List<Map<String, Object>> list2 = studentMapper.testTrimWhere(1, "");
for (Map<String, Object> map : list2) {
System.out.println(map);
}
List<Map<String, Object>> list3 = studentMapper.testTrimWhere(2, "学生2");
for (Map<String, Object> map : list3) {
System.out.println(map);
}
List<Map<String, Object>> list4 = studentMapper.testTrimWhere(null, null);
for (Map<String, Object> map : list4) {
System.out.println(map);
}
}
@Test
public void testSetTrim() {
studentMapper.testSetTrim(1, "zhangsan2");
List<Map<String, Object>> list = studentMapper.testWhere01(1, null);
for (Map<String, Object> map : list) {
System.out.println(map);
}
}
(4) 测试结果:
【f】foreach标签
foreach标签:主要用在构建in条件中,迭代一个集合.
item: 表示集合中每一个元素进行迭代时的别名,
index: 指 定一个名字,用于表示在迭代过程中,每次迭代到的位置,
open: 表示该语句以什么开始,
separator: 表示在每次进行迭代之间以什么符号作为分隔符,
close: 表示以什么结束。
(1) mapper接口:
/**
* foreach
*/
List<Map<String, Object>> testForEach(@Param("pkids") List<Integer> pkids);
(2) mapper映射文件:
<!--foreach-->
<select id="testForEach" resultType="map">
select * from tbl_student t
where 1 = 1
and t.s_id in
/*
foreach标签:主要用在构建in条件中,迭代一个集合
item: 表示集合中每一个元素进行迭代时的别名,
index: 指 定一个名字,用于表示在迭代过程中,每次迭代到的位置,
open: 表示该语句以什么开始,
separator: 表示在每次进行迭代之间以什么符号作为分隔符,
close: 表示以什么结束。
*/
<foreach collection="pkids" open="(" close=")" separator="," index="index" item="pkid">
#{pkid}
</foreach>
</select>
(3) 测试用例:
@Test
public void testForEach() {
List<Map<String, Object>> list = studentMapper.testForEach(Arrays.asList(1, 2, 3, 4, 5));
for (Map<String, Object> map : list) {
System.out.println(map);
}
}
(4) 测试结果:
【g】 sql标签
sql片段:就是预先定义后的一些sql语句。等其他sql需要的时候直接拿来用
id : sql片段的唯一标识,在需要引用sql片段的时候使用 <include refid="student_column"/> 标签引入即可;
尽量使用单表的字段来定义sql片段,重用性高
(1) mapper接口:
/**
* sql
*/
List<Map<String, Object>> testSql();
(2) mapper映射文件:
<!--sql-->
<!--
sql片段:就是预先定义后的一些sql语句。等其他sql需要的时候直接拿来用
id : sql片段的唯一标识,在需要引用sql片段的时候使用 <include refid="student_column"/> 标签引入即可
尽量使用单表的字段来定义sql片段,重用性高
-->
<sql id="student_column">
s_id,
s_name
</sql>
<select id="testSql" resultType="map">
select
<include refid="student_column"/>
from tbl_student
</select>
(3) 测试用例:
@Test
public void testSql() {
List<Map<String, Object>> list = studentMapper.testSql();
for (Map<String, Object> map : list) {
System.out.println(map);
}
}
(4) 测试结果:
三、总结
以上就是关于Mybatis中动态SQL部分的一些认识和使用详解,本文只是笔者学习上的一些见解和总结,希望对大家的学习有所帮助。