动态 SQL是MyBatis强大特性之一。极大的简化拼装 SQL的操作。 常用的几种元素如下:
if choose (when, otherwise) trim (where, set) foreach判断语句,常常与test属性联合使用。
<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和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>test 判断表达式(OGNL),遇见特殊符号应该去写转义字符。
<if test="id!=null"> id=#{id} </if> <if test="lastName!=null && lastName!="""> and last_name like #{lastName} </if> <if test="email!=null and email.trim()!="""> and email=#{email} </if> <!-- ognl会进行字符串与数字的转换判断 "0"==0 --> <if test="gender==0 or gender==1"> and gender=#{gender} </if>choose、when、otherwise 类似 switch .. case .. default
提供了title就按title查找,提供了author就按author查找的情形,若两者都没有提供,就返回所有符合条件的 BLOG
<select id="findActiveBlogLike" resultType="Blog"> SELECT * FROM BLOG WHERE state = ‘ACTIVE’ <choose> <when test="title != null"> AND title like #{title} </when> <when test="author != null and author.name != null"> AND author_name like #{author.name} </when> <otherwise> AND featured = 1 </otherwise> </choose> </select>现在回到if示例,这次我们将ACTIVE = 1也设置成动态的条件,看看会发生什么
<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> </select>如果这些条件没有一个能匹配上会发生什么?最终这条 SQL 会变成这样
SELECT * FROM BLOG WHERE这会导致查询失败。如果仅仅第二个条件匹配又会怎样?这条 SQL 最终会是这样:
SELECT * FROM BLOG WHERE AND title like ‘someTitle’这个查询也会失败。这个问题不能简单地用条件句式来解决。
MyBatis 有一个简单的处理,这在 90% 的情况下都会有用。而在不能使用的地方,你可以自定义处理方式来令其正常工作。一处简单的修改就能达到目的。
<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元素只会在至少有一个子元素的条件返回 SQL 子句的情况下才去插入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关键字,同时也会删掉无关的逗号,因为用了条件语句之后很可能就会在生成的 SQL 语句的后面留下这些逗号。
<trim prefix="SET" suffixOverrides=","> ... </trim>动态 SQL 的另外一个常用的操作需求是对一个集合进行遍历,通常是在构建 IN 条件语句的时候
<select id="selectPostIn" resultType="domain.blog.Post"> SELECT * FROM POST P WHERE ID in <foreach item="item" index="index" collection="list" open="(" separator="," close=")"> #{item} </foreach> </select>foreach元素的功能非常强大,它允许你指定一个集合,声明可以在元素体内使用的集合项(item)和索引(index)变量。它也允许你指定开头与结尾的字符串以及在迭代结果之间放置分隔符。这个元素是很智能的,因此它不会偶然地附加多余的分隔符
注意:你可以将任何可迭代对象(如 List、Set 等)、Map对象或者数组对象传递给foreach作为集合参数。当使用可迭代对象或者数组时,index 是当前迭代的次数,item 的值是本次迭代获取的元素。当使用 Map 对象(或者 Map.Entry 对象的集合)时,index 是键,item 是值。
bind元素可以从 OGNL表达式中创建一个变量并将其绑定到上下文
<select id="selectBlogsLike" resultType="Blog"> <bind name="pattern" value="'%' + _parameter.getTitle() + '%'" /> SELECT * FROM BLOG WHERE title LIKE #{pattern} </select>注意:OGNL语法
一个配置了_databaseId变量的 databaseIdProvider 可用于动态代码中,这样就可以根据不同的数据库厂商构建特定的语句
<insert id="insert"> <selectKey keyProperty="id" resultType="int" order="BEFORE"> <if test="_databaseId == 'oracle'"> select seq_users.nextval from dual </if> <if test="_databaseId == 'db2'"> select nextval for seq_users from sysibm.sysdummy1" </if> </selectKey> insert into users values (#{id}, #{name}) </insert>OGNL( Object Graph Navigation Language )对象图导航语言,这是一种强大的 表达式语言,通过它可以非常方便的来操作对象属性。 |描述|用法| |:|:| |访问对象属性|person.name| |调用方法| person.getName()| |调用静态属性/方法| @java.lang.Math@PI @java.util.UUID@randomUUID() | |调用构造方法| new com.bean.Person(‘admin’).name | |运算符| +,-*,/,% | |逻辑运算符| in,not in,>,>=,<,<=,==,!= 注意:xml中特殊符号如”,>,<等这些都需要使用转义字符|
更多内容: 可以查看OGNL语法
官方文档 http://www.atguigu.com/download.shtml#MyBatis
