MyBatis提供了动态SQL帮助我们解决在业务过程中,我们根据不同的条件动态生成SQL语句,用来满足各种复杂的查询需求,包括MyBatis中常用的动态SQL标签和用法,这种方式在一定程度上帮助我们重复写许多SQL堆积在一起,下面我们就看一下Mybatis中常用的有哪些动态SQL标签以及他的用法:
if
<if>
:用来表示条件判断,根据我们的条件动态生成SQL片段。在实际开发中,算是我们用的最多的一种动态SQL条件判断字段是加入SQL中还是不加入SQL语句中。
<select id="getUser" resultType="com.example.User">
SELECT * FROM users
WHERE 1=1
<if test="name != null and name != ''">
AND name = #{name}
</if>
<if test="age != null">
AND age = #{age}
</if>
</select>
上述代码中,我们使用了<if>
语句来判断,上述语句的 name != null and name != ''
表示,当传过来的name 字段的值不为空,并且name 传过来的是不是空字符串,那么我们就通过 将<if >
语句内部的SQL语句添加进去。实际上If 标签,就是通过test属性的表达式进行判断,当表达式的结果为true,那么标签中的内容就会执行,否则就直接被忽略掉。
where
<where>
: where一般和if结合使用:
- 当where 标签中的if条件都不满足的时候,则where标签没有任何功能,那就不会添加任何的where关键字。
- 当where标签中的if条件有满足或者全部满足的时候,那么where标签会自动添加where关键字,并将条件最前方多余的and去掉。
ps: where标签不能去掉条件最后多余的and标签
<select id="getUser" resultType="com.example.User">
SELECT * FROM users
<where>
<if test="name != null and name != ''">
AND name = #{name}
</if>
<if test="age != null">
AND age = #{age}
</if>
</where>
</select>
trim标签
<trim>
:用于去除或添加SQL片段的前缀或后缀。
常用属性:
prefix
: 在trim标签中的内容的前面添加某些内容。prefixOverrides
: 在trim标签中的内容的前面去掉某些内容。suffix
:在trim标签中内容的后面添加某些内容。suffixOverrides
: 在trim标签中的内容的后面去掉某些内容。
<select id="getEmpListByMoreTJ" resultType="Emp">
select * from users
<trim prefix="where" suffixOverrides="and">
<if test="name != '' and name != null">
name = #{ename} and
</if>
<if test="age != '' and age != null">
age = #{age} and
</if>
<if test="sex != '' and sex != null">
sex = #{sex}
</if>
</trim>
</select>
<trim prefix="where" suffixOverrides="and">
:在<trim>
标签中添加了前缀where,并通过suffixOverrides="and"去除了最后一个条件中的and。
根据不同的条件值,动态生成了查询语句的条件部分。如果ename、age和sex参数都有值,则生成完整的查询条件;如果某个参数没有值,则不生成对应的条件。
上述示例中使用了#{}占位符来引用参数值,这是为了防止SQL注入攻击。确保传递给SQL语句的参数值被正确地转义和处理。
choose、when、otherwise
<choose>
、<when>
、<otherwise>
:用于多条件判断,类似于Java中的switch语句。也可以说是if ...else if ... else
<select id="getUser" resultType="com.example.User">
SELECT * FROM users
WHERE 1=1
<choose>
<when test="name != null">
AND name = #{name}
</when>
<when test="age != null">
AND age = #{age}
</when>
<otherwise>
AND status = 'ACTIVE'
</otherwise>
</choose>
</select>
在上述示例中,根据name和age参数的值,动态生成了不同的查询条件:
如果name参数不为null,则生成AND name = #{name}的条件。
如果age参数不为null,则生成AND age = #{age}的条件。
如果以上两个条件都不成立(即name和age都为null),则生成AND status = 'ACTIVE’的条件。
<choose>
标签用于多条件判断,类似于Java中的switch语句。在<choose>
标签中,可以包含多个<when>
标签和一个<otherwise>
标签。
<when>
标签用于指定条件成立时生成的SQL片段。在每个<when>
标签中,通过test属性来判断条件是否成立。
<otherwise>
标签用于指定所有条件都不成立时生成的SQL片段。
通过使用、和标签,可以根据不同的条件值动态生成不同的SQL片段,实现灵活的条件判断和SQL拼接。这样可以满足复杂查询需求,同时保持SQL语句的可读性和可维护性。
foreach
<foreach>
:用于遍历集合或数组,生成重复的SQL片段。
<!--int insertMoreEmp(List<Emp> emps);-->
<insert id="insertMoreEmp">
insert into t_emp values
<foreach collection="emps" item="emp" separator=",">
(null,#{emp.ename},#{emp.age},#{emp.sex},#{emp.email},null)
</foreach>
</insert>
<!--int deleteMoreByArray(int[] eids);-->
<delete id="deleteMoreByArray">
delete from t_emp where
<foreach collection="eids" item="eid" separator="or">
eid = #{eid}
</foreach>
</delete>
<!--int deleteMoreByArray(int[] eids);-->
<delete id="deleteMoreByArray">
delete from t_emp where eid in
<foreach collection="eids" item="eid" separator="," open="(" close=")">
#{eid}
</foreach>
</delete>
<insert>
标签示例:
<insert id="insertMoreEmp">
insert into t_emp values
<foreach collection="emps" item="emp" separator=",">
(null,#{emp.ename},#{emp.age},#{emp.sex},#{emp.email},null)
</foreach>
</insert>
使用了<foreach>
标签来遍历emps集合,将集合中的每个Emp对象的属性值插入到t_emp表中。
public int insertMoreEmp(List<Emp> emps) {
try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
EmpMapper empMapper = sqlSession.getMapper(EmpMapper.class);
return empMapper.insertMoreEmp(emps);
}
}
public static void main(String[] args) {
List<Emp> emps = new ArrayList<>();
// 添加要插入的Emp对象到emps集合中
Emp emp1 = new Emp();
emp1.setEname("John");
emp1.setAge(25);
emp1.setSex("Male");
emp1.setEmail("john@example.com");
emps.add(emp1);
Emp emp2 = new Emp();
emp2.setEname("Jane");
emp2.setAge(30);
emp2.setSex("Female");
emp2.setEmail("jane@example.com");
emps.add(emp2);
// 调用insertMoreEmp方法进行批量插入
int rowsAffected = insertMoreEmp(emps);
System.out.println(rowsAffected + " rows inserted.");
}
<delete>
标签示例(使用or连接条件)
<delete id="deleteMoreByArray">
delete from t_emp where
<foreach collection="eids" item="eid" separator="or">
eid = #{eid}
</foreach>
</delete>
在上述示例中,使用了<foreach>
标签来遍历eids数组,将数组中的每个元素作为删除条件的一部分,使用or连接多个条件。
public int deleteMoreByArray(int[] eids) {
try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
EmpMapper empMapper = sqlSession.getMapper(EmpMapper.class);
return empMapper.deleteMoreByArray(eids);
}
}
public static void main(String[] args) {
int[] eids = {1, 2, 3}; // 要删除的eid数组
// 调用deleteMoreByArray方法进行批量删除
int rowsAffected = deleteMoreByArray(eids);
System.out.println(rowsAffected + " rows deleted.");
}
<delete>
标签示例(使用in连接条件):
<delete id="deleteMoreByArray">
delete from t_emp where eid in
<foreach collection="eids" item="eid" separator="," open="(" close=")">
#{eid}
</foreach>
</delete>
公共SQL片段
在Mapper.xml文件中,我们对可以通过记录一段公共的SQL片段,在使用的地方通过include标签进行引入。
示例:
<sql id="empColumns">
eid,ename,age,sex,did
</sql>
使用:
select <include refid="empColumns"></include> from t_emp