这里写目录标题
一、动态SQL概念
1、什么是动态SQL
动态SQL是MyBatis的核心特性之一,允许根据条件动态拼接SQL语句。通过条件判断、循环等逻辑,灵活生成不同场景下的SQL,解决传统JDBC中硬编码的SQL繁琐问题。
2、核心使用场景
- 多条件查询:根据参数动态拼接WHERE条件。
- 批量操作:处理批量插入、更新或删除。
- 可选字段更新:只更新非空字段。
- 动态表名/列名:根据业务需求切换表结构。
二、标签属性
1、if标签
if标签可以通过test属性的表达式进行判断,若表达式的结果为true,则标签中的内容会执行,反之标签中的内容不会执行。
DynamicSqlMapper接口
java
public interface DynamicSQLMapper {
//多条件查询
List<Emp> getEmpByCondition(Emp emp);
}
DynamicSqlMapper.xml
xml
<select id="getEmpByCondition" resultType="Emp">
select * from t_emp where 1=1
<if test="empName != null and empName != ''">
and emp_name = #{empName}
</if>
<if test="age != null and age != ''">
and age = #{age}
</if>
<if test="email != null and email != ''">
and email = #{email}
</if>
<if test="sex != null and sex != ''">
and sex = #{sex}
</if>
</select>
上述xml代码中加上1=1使得:即使emp_name为空,也不会导致sql语句变成:where and xxx。
测试文件:
java
@Test
public void testGetEmpByCondition() throws IOException {
SqlSession sqlSession = SqlSessionUtils.getSqlSession();
DynamicSQLMapper mapper = sqlSession.getMapper(DynamicSQLMapper.class);
Emp emp=new Emp();
List<Emp> depts=mapper.getEmpByCondition(emp);
depts.stream().forEach(a->{
System.out.println(a);
});
}
2、where标签
上述i标签中我们使用了where 1=1来解决if标签里面的and会造成的sql语句报错的问题,也可以使用where标签,自动解决and,or,where的添加删除问题。
- 当where标签中有内容时,会自动生成where关键字,并将内容前多余的and或者or去掉。
- 当where标签中没有内容时,此时where标签没有任何效果。
注意:where标签不能将其中内容厚民多余的and或or去掉。
DynamicSqlMapper接口
java
List<Emp> queryEmpByCondition(Emp emp);
DynamicSqlMapper.xml
xml
<select id="queryEmpByCondition" resultType="Emp">
select * from t_emp
<where>
<if test="empName != null and empName != ''">
and emp_name = #{empName}
</if>
<if test="age != null and age != ''">
and age = #{age}
</if>
<if test="email != null and email != ''">
and email = #{email}
</if>
<if test="sex != null and sex != ''">
and sex = #{sex}
</if>
</where>
</select>
测试类
java
@Test
public void testQueryEmpByCondition() throws IOException {
SqlSession sqlSession = SqlSessionUtils.getSqlSession();
DynamicSQLMapper mapper = sqlSession.getMapper(DynamicSQLMapper.class);
Emp emp=new Emp();
List<Emp> depts=mapper.queryEmpByCondition(emp);
depts.stream().forEach(a->{
System.out.println(a);
});
}
3、set标签
在更新的语句当中再加上set标签,可以出去更新语句中无用的逗号。
DynamicSqlMapper接口
java
int updateEmp(Emp emp);
DynamicSqlMapper.xml
xml
<update id="updateEmp">
UPDATE t_emp
<set>
<if test="empName != null and empName != ''">
emp_name = #{empName}
</if>
<if test="age != null and age != ''">
age = #{age}
</if>
<if test="email != null and email != ''">
email = #{email}
</if>
<if test="sex != null and sex != ''">
sex = #{sex}
</if>
</set>
where eid = #{eid}
</update>
测试类
java
@Test
public void testUpdateEmp() throws IOException {
SqlSession sqlSession = SqlSessionUtils.getSqlSession();
DynamicSQLMapper mapper = sqlSession.getMapper(DynamicSQLMapper.class);
Emp emp=new Emp();
emp.setEid(1);
emp.setEmpName("PPP");
int i =mapper.updateEmp(emp);
System.out.println(i);
}
4、trim标签
在 MyBatis 的动态 SQL 中, 标签用于处理 SQL 片段的前缀和后缀,常用于动态添加或移除多余的 SQL 关键字(如 WHERE、AND、OR、逗号等),从而避免因动态条件拼接导致的语法错误。
- trim标签有内容时:
- prefix/suffix 在trim标签中内容前面或者后面去添加指定内容
- prefixOverrides/suffixOverrides 在trim标签中内容前面或后面去删除指定内容
- 若标签没有内容时:trim标签也没有任何效果
DynamicSqlMapper接口
java
List<Emp> getEmpByTrimCondition(Emp emp);
DynamicSqlMapper.xml
xml
<select id="getEmpByTrimCondition" resultType="Emp">
select * from t_emp
<trim prefix="where" suffixOverrides="and|or">
<if test="empName != null and empName != ''">
emp_name = #{empName} and
</if>
<if test="age != null and age != ''">
age = #{age} or
</if>
<if test="email != null and email != ''">
email = #{email} and
</if>
<if test="sex != null and sex != ''">
sex = #{sex}
</if>
</trim>
</select>
上述xml代码中,当trim标签内有内容的时候, prefix="where",suffixOverrides="and|or"生效,即:在标签内容前加上where,在标签内容后去掉and或者or。
测试类
java
@Test
public void testGetEmpByTrimCondition() throws IOException {
SqlSession sqlSession = SqlSessionUtils.getSqlSession();
DynamicSQLMapper mapper = sqlSession.getMapper(DynamicSQLMapper.class);
List<Emp> emp1 = mapper.getEmpByTrimCondition(new Emp(null, "Apple", 22, "女", "123@gmail.com"));
List<Emp> emp2 = mapper.getEmpByTrimCondition(new Emp(null, "Apple", null, "女", "123@gmail.com"));
List<Emp> emp3 = mapper.getEmpByTrimCondition(new Emp(null, null, null, "女", "123@gmail.com"));
System.out.println(emp1);
System.out.println(emp2);
System.out.println(emp3);
}
5、choose/when/otherwise
标签作用:
- :包裹多个 和 ,表示一个条件分支组。
- :定义条件分支(类似 if 或 else if),通过 test 属性判断是否执行。
- :默认分支(类似 else),当所有 都不满足时执行。
DynamicSqlMapper接口
java
List<Emp> getEmpByChoose(Emp emp);
DynamicSqlMapper.xml
xml
<select id="getEmpByChoose" resultType="Emp">
select * from t_emp
<where>
<choose>
<when test="empName != null and empName != ''">
emp_name = #{empName}
</when>
<when test="age != null and age != ''">
age = #{age}
</when>
<when test="sex != null and sex != ''">
sex = #{sex}
</when>
<when test="email != null and email != ''">
email = #{email}
</when>
<otherwise>
did = 1
</otherwise>
</choose>
</where>
</select>
上述代码中choose表示一个条件分支组,里面的when或者otherwise相当于if,else的条件判断。
测试类
java
@Test
public void testGetEmpByTrimCondition() throws IOException {
SqlSession sqlSession = SqlSessionUtils.getSqlSession();
DynamicSQLMapper mapper = sqlSession.getMapper(DynamicSQLMapper.class);
List<Emp> emp1 = mapper.getEmpByTrimCondition(new Emp(null, "Apple", 22, "女", "123@gmail.com"));
List<Emp> emp2 = mapper.getEmpByTrimCondition(new Emp(null, "Apple", null, "女", "123@gmail.com"));
List<Emp> emp3 = mapper.getEmpByTrimCondition(new Emp(null, null, null, "女", "123@gmail.com"));
System.out.println(emp1);
System.out.println(emp2);
System.out.println(emp3);
}
6、foreach标签
foreach 标签可以用来遍历数组、列表和 Map 等集合参数,实现批量操作或一些简单 SQL 操作。
- collection:要被 foreach 标签循环解析的对象。
- item:集合中元素迭代时的别名,该参数为必选。
- index:在list和数组中,index是元素的徐浩,在map中,index是元素的key。该参数可选。
- open:foreach代码的开始符号,一般是"(",和close=")"合用。
- separator:元素之间的分隔符,例如在 in() 的时候,separator="," 会自动在元素中间用 "," 隔开,避免手动输入逗号导致 SQL 错误,如 in(1, 2,) 这样。该参数可选。
- close:foreach 代码的关闭符号,一般是 ")",和 open="(" 合用。常用在 in(),values()时。该参数可选。
注意
foreach 标签的 collection 属性在接受参数名时,有两种情况:- 匿名参数
- 当在 java 方法中没有通过 @Param 注解指定参数名时,列表类型默认参数名为 "list",数组类型默认参数名为 "array",Map 对象没有默认值。
- 具名参数
- java 方法中使用了 @Param 注解指定了参数名称,则 foreach 中的 collection 属性必须为参数名。
6.1实现批量删除
DynamicSqlMapper接口
java
int deleteByArray(@Param("eids") Integer[] eids);
DynamicSqlMapper.xml
xml
<delete id="deleteByArray">
delete from t_emp where eid in
<foreach collection="eids" item="eid" separator="," open="(" close=")">
#{eid}
</foreach>
</delete>
这段代码也可以用or的方式实现
xml
<delete id="deleteMoreByArray">
<!--方法2:-->
delete from t_emp where
<foreach collection="eids" item="eid" separator="or">
eid = #{eid}
</foreach>
</delete>
测试类
java
@Test
public void testInsertMoreByList() throws IOException {
SqlSession sqlSession = SqlSessionUtils.getSqlSession();
DynamicSQLMapper mapper = sqlSession.getMapper(DynamicSQLMapper.class);
Emp emp1 = new Emp(null, "Mary", 23, "女", "11111@qq.com");
Emp emp2 = new Emp(null, "Linda", 23, "女", "1144111@qq.com");
Emp emp3 = new Emp(null, "Jackoline", 23, "女", "1122111@qq.com");
List<Emp> emps = Arrays.asList(emp1, emp2, emp3);
System.out.println(mapper.insertMoreByList(emps));
}
6.2实现批量添加
DynamicSqlMapper接口
java
int insertMoreByList(@Param("emps") List<Emp> emps);
DynamicSqlMapper.xml
xml
<insert id="insertMoreByList">
insert into t_emp values
<foreach collection="emps" item="emp" separator=",">
(null, #{emp.empName}, #{emp.age}, #{emp.sex}, #{emp.email}, null)
</foreach>
</insert>
测试类
java
@Test
public void testInsertMoreByList() throws IOException {
SqlSession sqlSession = SqlSessionUtils.getSqlSession();
DynamicSQLMapper mapper = sqlSession.getMapper(DynamicSQLMapper.class);
Emp emp1 = new Emp(null, "Mary", 23, "女", "11111@qq.com");
Emp emp2 = new Emp(null, "Linda", 23, "女", "1144111@qq.com");
Emp emp3 = new Emp(null, "Jackoline", 23, "女", "1122111@qq.com");
List<Emp> emps = Arrays.asList(emp1, emp2, emp3);
System.out.println(mapper.insertMoreByList(emps));
}
7、include/sql标签
在 MyBatis 的动态 SQL 中,可抽取的可复用片段可以通过 和 标签实现。这种方式可以将重复的 SQL 片段提取出来,统一维护,减少代码冗余,提升可读性和可维护性。
- :定义可复用的 SQL 片段。
- :引用已定义的 SQL 片段。
DynamicSqlMapper接口
java
List<Emp> getAllEmpNameAndAge();
xml
<sql id="empColumns">emp_name, age</sql>
<select id="getAllEmpNameAndAge" resultType="Emp">
select <include refid="empColumns"></include> from t_emp
</select>
三、特殊字符
<![CDATA[ ]]> 在mybatis、ibatis等书写SQL的xml中比较常见,是一种XML语法,他的作用是 可以忽略xml的转义(在该标签中的语句和字符原本是什么样的,在拼接成SQL后还是什么样的)