MyBatis之动态SQL:if、choose、when、otherwise、where、
。。。
动态 SQL 是 MyBatis 的强⼤特性之⼀。如果你使⽤过 JDBC 或其它类似的框架,你应该能理解根据不同条件拼接 SQL 语句有多痛苦,例如拼接时要确保不能忘记添加必要的空格,还要注意去掉列表最后⼀个列名的逗号。利⽤动态 SQL,可以彻底摆脱这种痛苦。
使⽤动态 SQL 并⾮⼀件易事,但借助可⽤于任何 SQL 映射语句中的强⼤的动态 SQL 语⾔,MyBatis 显著地提升了这⼀特性的易⽤性。
如果你之前⽤过 JSTL 或任何基于类 XML 语⾔的⽂本处理器,你对动态 SQL 元素可能会感觉似曾相识。在 MyBatis 之前的版本中,需要花时间了解⼤量的元素。借助功能强⼤的基于 OGNL 的表达式,MyBatis 3 替换了之前的⼤部分元素,⼤⼤精简了元素种类,现在要学习的元素种类⽐原来的⼀半还要少。
⼀、if —— 只要为true就加上后⾯的sql
使⽤动态 SQL 最常见情景是根据条件包含 where ⼦句的⼀部分。⽐如:
pta二叉树的遍历<select id="findActiveBlogWithTitleLike" resultType="Blog">
SELECT * FROM BLOG
WHERE state = ‘ACTIVE’
<if test="title != null">
AND title like #{title}
</if>
</select>
这条语句提供了可选的查⽂本功能。如果不传⼊ “title”,那么所有处于 “ACTIVE” 状态的 BLOG 都会返回;如果传⼊了 “title” 参数,那么就会对 “title” ⼀列进⾏模糊查并返回对应的 BLOG 结果(细⼼的读者可能会发现,“title” 的参数值需要包含查掩码或通配符字符)。
如果希望通过 “title” 和 “author” 两个参数进⾏可选搜索该怎么办呢?⾸先,我想先将语句名称修改成更名副其实的名称;接下来,只需要加⼊另⼀个条件即可。
<select id="findActiveBlogLike" resultType="Blog">
SELECT * FROM BLOG WHERE state = ‘ACTIVE’
<if test="title != null">
AND title like #{title}
</if>
<if test="author != null and author.name != null">
AND author_name like #{author.name}
</if>
</select>
⼆、choose、when、otherwise —— 从多个条件中只选择⼀个使⽤,碰到⼀个when为true就返回
有时候,我们不想使⽤所有的条件,⽽只是想从多个条件中选择⼀个使⽤。⽽使⽤if标签时,只要test中的表达式为 true,就会执⾏ if 标签中的条件。针对这种情况,MyBatis 提供了 choose 元素,它有点像 Java 中的 switch 语句。
choose标签是按顺序判断其内部when标签中的test条件出否成⽴,如果有⼀个成⽴,则 choose 结束。当 choose 中所有 when 的条件都不满则时,则执⾏ otherwise 中的sql。类似于Java 的 switch 语句,choose 为 switch,when 为 case,otherwise 则为 default。
还是上⾯的例⼦,但是策略变为:传⼊了 “title” 就按 “title” 查,传⼊了 “author” 就按 “author” 查的情形。若两者都没有传⼊,就返回标记为 featured 的 BLOG(这可能是管理员认为,与其返回⼤量的⽆意义随机 Blog,还不如返回⼀些由管理员精选的 Blog)。
<select id="findActiveBlogLike"
高级的ppt背景图片resultType="Blog">
SELECT * FROM BLOG WHERE state = ‘ACTIVE’
<choose>
<when test="title != null">
AND title like #{title}mysql语句的执行顺序
</when>
<when test="author != null and author.name != null">
AND author_name like #{author.name}
</when>
<otherwise>
AND featured = 1
</otherwise>
</choose>
</select>
三、trim、where、set
前⾯⼏个例⼦已经⽅便地解决了⼀个臭名昭著的动态 SQL 问题。现在回到之前的 “if” ⽰例,这次我们将 “state = ‘ACTIVE’” 设置成动态条件,看看会发⽣什么。
<select id="findActiveBlogLike"
resultType="Blog">
SELECT * FROM BLOG
WHERE
<if test="state != null">
state = #{state}
</if>
<if test="title != null">
AND title like #{title}
</if>
<if test="author != null and author.name != null">
a layer ofAND author_name like #{author.name}
</if>
</select>
如果没有匹配的条件会怎么样?最终这条 SQL 会变成这样:
SELECT * FROM BLOG
WHERE
这会导致查询失败。如果匹配的只是第⼆个条件⼜会怎样?这条 SQL 会是这样:
SELECT * FROM BLOG
WHERE
AND title like ‘someTitle’
这个查询也会失败。这个问题不能简单地⽤条件元素来解决。这个问题是如此的难以解决,以⾄于解决过的⼈不会再想碰到这种问题。
MyBatis 有⼀个简单且适合⼤多数场景的解决办法。⽽在其他场景中,可以对其进⾏⾃定义以符合需求。⽽这,只需要⼀处简单的改动:
<select id="findActiveBlogLike"
resultType="Blog">
SELECT * FROM BLOG
<where>
<if test="state != null">
state = #{state}
</if>
<if test="title != null">
AND title like #{title}
</if>
<if test="author != null and author.name != null">
AND author_name like #{author.name}
</if>
</where>
</select>
where元素只会在⼦元素返回任何⾄少⼀个内容的情况下才插⼊ “WHERE” ⼦句。⽽且,若⼦句的开头为 “AND” 或 “OR”,where元素也会将它们去除。
如果where元素与你期望的不太⼀样,你也可以通过⾃定义 trim 元素来定制where元素的功能。⽐如,和where元素等价的⾃定义trim 元素为:
<trim prefix="WHERE" prefixOverrides="AND |OR ">
...
</trim>
prefixOverrides属性会忽略通过管道符分隔的⽂本序列(注意此例中的空格是必要的)。上述例⼦会移除所有prefixOverrides属性中指定的内容,并且插⼊prefix属性中指定的内容。
⽤于动态更新语句的类似解决⽅案叫做set。set元素可以⽤于动态包含需要更新的列,忽略其它不更新的列。⽐如:
<update id="updateAuthorIfNecessary">
update Author
<set>
<if test="username != null">username=#{username},</if>
<if test="password != null">password=#{password},</if>
<if test="email != null">email=#{email},</if>
<if test="bio != null">bio=#{bio}</if>
</set>
where id=#{id}
</update>
易语言软件开头特效源码 这个例⼦中,set元素会动态地在⾏⾸插⼊ SET 关键字,并会删掉额外的逗号(这些逗号是在使⽤条件语句给列赋值时引⼊的)。
来看看与set元素等价的⾃定义trim元素吧:
<trim prefix="SET" suffixOverrides=",">
...
</trim>
注意,我们覆盖了后缀值设置,并且⾃定义了前缀值。
四、动态SQL: SQL ⽚段
有时候可能某个 sql 语句我们⽤的特别多,为了增加代码的重⽤性,简化代码,我们需要将这些代码抽取出来,然后使⽤时直接调⽤。 ⽐如:假如我们需要经常根据⽤户名和性别来进⾏联合查询,那么
我们就把这个代码抽取出来,如下:
<!-- 定义 sql ⽚段 -->
<sql id="selectUserByUserNameAndSexSQL">
<if test="username != null and username != ''">
AND username = #{username}
</if>
<if test="sex != null and sex != ''">
AND sex = #{sex}
</if>
</sql>
引⽤ sql ⽚段
<select id="selectUserByUsernameAndSex" resultType="user" parameterType="com.ys.po.User">
select * from user
<trim prefix="where" prefixOverrides="and | or">用smart原则做一个计划
<!-- 引⽤ sql ⽚段,如果refid 指定的不在本⽂件中,那么需要在前⾯加上 namespace -->
<include refid="selectUserByUserNameAndSexSQL"></include>
<!-- 在这⾥还可以引⽤其他的 sql ⽚段 -->
</trim>
</select>
注意:①、最好基于单表来定义 sql ⽚段,提⾼⽚段的可重⽤性
②、在 sql ⽚段中最好不要包括 where
五、动态SQL: foreach 语句
需求:我们需要查询 user 表中 id 分别为1,2,3的⽤户
sql语句:select * from user where id=1 or id=2 or id=3
select * from user where id in (1,2,3)
1、建⽴⼀个 UserVo 类,⾥⾯封装⼀个 List<Integer> ids 的属性
2、我们⽤ foreach 来改写 select * from user where id=1 or id=2 or id=3
<select id="selectUserByListId" parameterType="com.ys.vo.UserVo" resultType="com.ys.po.User">
select * from user
<where>
<!--
collection:指定输⼊对象中的集合属性
item:每次遍历⽣成的对象
open:开始遍历时的拼接字符串
close:结束时拼接的字符串
separator:遍历对象之间需要拼接的字符串
select * from user where 1=1 and (id=1 or id=2 or id=3)
-->
<foreach collection="ids" item="id" open="and (" close=")" separator="or">
id=#{id}
</foreach>
</where>
</select>
3、我们⽤ foreach 来改写 select * from user where id in (1,2,3)
<select id="selectUserByListId" parameterType="com.ys.vo.UserVo" resultType="com.ys.po.User">
select * from user
<where>
<!--
collection:指定输⼊对象中的集合属性
item:每次遍历⽣成的对象
open:开始遍历时的拼接字符串
close:结束时拼接的字符串
separator:遍历对象之间需要拼接的字符串
select * from user where 1=1 and id in (1,2,3)
-->
<foreach collection="ids" item="id" open="and id in (" close=") " separator=",">
#{id}
</foreach>
</where>
</select>
foreach元素的功能⾮常强⼤,它允许你指定⼀个集合,声明可以在元素体内使⽤的集合项(item)和索引(index)变量。它也允许你指定开头与结尾的字符串以及集合项迭代之间的分隔符。这个元素也不会错误地添加多余的分隔符,看它多智能!
提⽰:你可以将任何可迭代对象(如 List、Set 等)、Map 对象或者数组对象作为集合参数传递给foreach。当使⽤可迭代对象或者数组时,index 是当前迭代的序号,item 的值是本次迭代获取到的元素。当使⽤ Map 对象(或者 Map.Entry 对象的集合)时,index 是
键,item 是值。
六、script
要在带注解的映射器接⼝类中使⽤动态 SQL,可以使⽤script元素。⽐如:
@Update({"<script>",
"update Author",
" <set>",
" <if test='username != null'>username=#{username},</if>",
" <if test='password != null'>password=#{password},</if>",
" <if test='email != null'>email=#{email},</if>",
" <if test='bio != null'>bio=#{bio}</if>",
" </set>",
"where id=#{id}",
"</script>"})
void updateAuthorValues(Author author);
七、bind
bind 元素允许你在 OGNL 表达式以外创建⼀个变量,并将其绑定到当前的上下⽂。⽐如:
<select id="selectBlogsLike" resultType="Blog">
<bind name="pattern" value="'%' + _Title() + '%'"/>
SELECT * FROM BLOG
WHERE title LIKE #{pattern}
</select>
其实动态 sql 语句的编写往往就是⼀个拼接的问题,为了保证拼接准确,我们最好⾸先要写原⽣的 sql 语句出来,然后在通过 mybatis 动态sql 对照着改,防⽌出错。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论