mybatis有一个强大的特性,其余框架在拼接sql的时候要特别谨慎,好比哪里须要空格,还要注意去掉列表最后一个列名的逗号,mybtis的动态sql能够帮助咱们逃离这样的痛苦挣扎,那就是动态SQL.它还能够处理一种状况,当你不肯定你的参数不知道是否是为空的时候,咱们不须要在业务逻辑中判断,直接在sql中处理,代码无比简洁。主要的动态sql标签以下:
java
注意事项:
在mapper中若是出现大于号(>),小于号(),大于等于号(),小于等于号()等,最好须要转换成为实体符号,这是由于mapper是XML文件,xml文件自己就含有较多的<>这样的尖括号,因此解析的时候可能会解析出错。sql
原符号 | < | <= | > | >= | & | ' | " |
---|---|---|---|---|---|---|---|
替换符号 | < |
<= |
> |
>= |
& |
' |
" |
咱们常常须要根据where后面的条件筛选出须要的数据,当多个条件拼接的时候,咱们通常使用<if></if>,若是if里面的条件成立,那么就会使用标签的语句,可是咱们能够知道where句子第一个标签是没有and的,然后面的条件都须要and,因此有一种作法是第一个使用where 1 = 1,这个条件恒成立,后面的全部子语句都加上and,若是增长判断,那么咱们只须要加<if>标签就能够了。数组
<!-- 动态sql if标签--> <!-- &可使用and来代替 ,注意!=须要连在一块儿写--> <select id="selectStudentByDynamicSQL" resultType="Student"> <!--最经常使用的(动态参数) select id,name,age,score from student where name like '%' #{name} '%' --> <!-- 下面的是字符串拼接 ,只能写value,了解便可,容易sql注入,执行效率低,不建议使用--> select id,name,age,score from student where 1=1 <if test="name != null and name != ''"> and name like '%' #{name} '%' </if> <if test="age > 0"> and age > #{age} </if> </select>
当有两个查询条件的时候,sql语句是:select * from student where 1=1 and name like '%' ? '%' and age > ?
当有一个查询条件的时候:sql语句就变成:select * from student where 1=1 and name like '%' ? '%'
当没有查询条件的时候,sql语句是:
select * from student where 1=1
<if></if>标签须要手动在where后面添加1=1语句,这是由于若是<if>后面的条件都是false的时候,where后面若是没有1=1语句,sql就剩下一个空空的where,sql就会报错。因此在where后面须要加上永真句子1=1,可是这样有一个问题,当数据量比较大的时候,会严重影响sql的查询效率。mybatis
使用<where></where>标签,在有查询语句的时候,自动补上where子句,在没有查询条件的时候,不会加上where子句,这也就解决了咱们上面所涉及到的问题,剩下的就是<if>标签的and子句,第一个,<if>片断里面能够不包含and,也能够包含,系统会自动去掉and,可是其余的<if>片断里面的and,必须写上,不然会出错。下面的写法中,若是name为null,第二个if标签中的if也会被去掉,不会报错。app
<select id="selectStudentByDynamicSQLWhere" resultType="Student"> <!--最经常使用的(动态参数) select id,name,age,score from student where name like '%' #{name} '%' --> <!-- 下面的是字符串拼接 ,只能写value,了解便可,容易sql注入,执行效率低,不建议使用--> select id,name,age,score from student <where> <if test="name != null and name != ''"> and name like '%' #{name} '%' </if> <if test="age > 0"> and age > #{age} </if> </where> </select>
若是where里面是不规范的,那咱们能够经过
下面这样的是错误的,当传入的name不为空,并且age大于0的时候ide
<select id="selectStudentByDynamicSQLWhere" resultType="Student"> select id,name,age,score from student <trim prefix="where" prefixOverrides="and"> <if test="name != null and name != ''"> name like '%' #{name} '%' </if> <if test="age > 0"> age > #{age} </if> </trim> </select>
不会本身增长and在第二个age前面:
下面的是正确的,咱们在两个<if>标签前面都增长了and,第二个and会自动去掉:code
<select id="selectStudentByDynamicSQLWhere" resultType="Student"> select id,name,age,score from student <trim prefix="where" prefixOverrides="and"> <if test="name != null and name != ''"> and name like '%' #{name} '%' </if> <if test="age > 0"> and age > #{age} </if> </trim> </select>
下面是后缀模式, prefix="set"
表示在整个语句前面加上前缀set, suffixoverride=","
表示每个语句后面的后缀","能够被忽略,若是是须要的话。suffix=" where id = #{id}
表示在整个语句后面增长where id = #{id},:xml
update user <trim prefix="set" suffixoverride="," suffix=" where id = #{id} "> <if test="name != null and name.length()>0"> name=#{name} , </if> <if test="age != null "> age=#{age} , </if> </trim>
固然,咱们对上面的语句还有动态解决的方案,那就是
<update id="updateStudent"> update student <set> <!-- 第一个if标签的逗号必定要有,最后一个标签的逗号能够没有--> <if test="name != null"> name=#{name},</if> <if test="age != null">age=#{age},</if> <if test="score != null"> score=#{score},</if> </set> where id=#{id} </update>
有时候,咱们只想去匹配第一个条件,或者第一个条件不匹配的时候才会去匹配第二个条件,不像<where></where>标签里面的<if></if>同样会去判断全部的子语句是否能够匹配,而是遇到一个匹配的就会执行跳出<choose></choose>
<!-- selectStudentByDynamicSQLChoose 相似于switch,知足后就不会判断后面的了--> <!-- 若是名字不为空,那么按照名字来查询,若是名字为空,就按照年龄来查询,若是没有查询条件,就没有查询条件 --> <select id="selectStudentByDynamicSQLChoose" resultType="Student"> <!--最经常使用的(动态参数) select id,name,age,score from student where name like '%' #{name} '%' --> select id,name,age,score from student <where> <choose> <when test="name != null and name != ''"> and name like '%' #{name} '%' </when> <when test="age > 0"> and age > #{age} </when> <otherwise> and 1 != 1 </otherwise> </choose> </where> </select>
<choose>标签就像是switch语句,每个<when>都像是case,后面默认跟上break语句,只要知足一个就不会判断后面的子语句了,当前面全部的<when></when>都不执行的时候,就会执行<otherwise></otherwise>标签的内容,这个内容也就像是switch语句里面的default。
动态SQL要有一个比较多的操做是对一个集合进行遍历,一般是在构建IN条件语句的时候。须要注意的点:
1.好比咱们须要查找学生的id为1,2,3的学生信息,咱们不但愿分开一次査一个,而是但愿将数组id一次传进去,查出来一个学生的集合。
sql接口能够这样写,传入一个对象的数组:
public List<Student>selectStudentByDynamicSQLForeachArray(Object[]studentIds);
sql语句以下,遍历array数组的时候,指定左边符号是左括号,右边是右括号,元素以逗号分隔开:
<!-- select * from student where id in (1,3) --> <select id="selectStudentByDynamicSQLForeachArray" resultType="Student"> select id,name,age,score from student <if test="array !=null and array.length > 0 "> where id in <foreach collection="array" open="(" close=")" item="myid" separator=","> #{myid} </foreach> </if> </select>
2.当遍历的是一个类型为int的list列表时:
public List<Student>selectStudentByDynamicSQLForeachList(List<Integer>studentIds);
sql语句以下,colleaction指定为list:
<select id="selectStudentByDynamicSQLForeachList" resultType="Student"> select id,name,age,score from student <if test="list !=null and list.size > 0 "> where id in <foreach collection="list" open="(" close=")" item="myid" separator=","> #{myid} </foreach> </if> </select>
3.当遍历的是一个类型为对象的list:
public List<Student>selectStudentByDynamicSQLForeachListStudent(List<Student>students);
sql语句里面与上面类似,只是在使用属性的时候不太同样:
<select id="selectStudentByDynamicSQLForeachListStudent" resultType="Student"> select id,name,age,score from student <if test="list !=null and list.size > 0 "> where id in <foreach collection="list" open="(" close=")" item="stu" separator=","> #{stu.id} </foreach> </if> </select>
用于定义sql片断,方便在其余SQL标签里面复用,在其余地方复用的时候须要使用<include></include>子标签,<sql>能够定义sql的任何部分,因此<include>标签能够放在动态SQL的任何位置。
<sql id="selectHead"> select id,name,age,score from student </sql> <!-- 可读性比较差 --> <select id="selectStudentByDynamicSQLfragment" resultType="Student"> <include refid="selectHead"></include> <if test="list !=null and list.size > 0 "> where id in <foreach collection="list" open="(" close=")" item="stu" separator=","> #{stu.id} </foreach> </if> </select>
动态sql让SQL写起来更加简洁,减小了不少重复代码,动态sql之间能够相互拼接,只要符合sql语句规范便可。
【做者简介】:
秦怀,公众号【秦怀杂货店】做者,技术之路不在一时,山高水长,纵使缓慢,驰而不息。这个世界但愿一切都很快,更快,可是我但愿本身能走好每一步,写好每一篇文章,期待和大家一块儿交流。