首先引用一段mybatis文档中的话:
动态 SQL
MyBatis 的强大特性之一便是它的动态 SQL。如果你有使用 JDBC 或其它类似框架的经验,你就能体会到根据不同条件拼接 SQL 语句的痛苦。例如拼接时要确保不能忘记添加必要的空格,还要注意去掉列表最后一个列名的逗号。利用动态 SQL 这一特性可以彻底摆脱这种痛苦。
虽然在以前使用动态 SQL 并非一件易事,但正是 MyBatis 提供了可以被用在任意 SQL 映射语句中的强大的动态 SQL 语言得以改进这种情形。
动态 SQL 元素和 JSTL 或基于类似 XML 的文本处理器相似。在 MyBatis 之前的版本中,有很多元素需要花时间了解。MyBatis 3 大大精简了元素种类,现在只需学习原来一半的元素便可。MyBatis 采用功能强大的基于 OGNL 的表达式来淘汰其它大部分元素。
一、if
二、where
三、set
四、trim
五、choose, when, otherwise
六、foreach
七、bind
下面记录各个元素的巧妙使用:
一、if
如果采用xml的方式配置mybatis,假设现在要做两个查询:
1.查询一个对象的所有记录。
2.查询一个对象所有记录中包含一个传过来的字符串的模糊查询。
那么不使用动态SQL应该这样写:(这样显得很麻烦)
<select id="productList" resultType="Product">
select p.id,p.name,p.price from product p
</select>
<select id="getProductsLikeName" parameterType="String" resultType="Product">
select p.id,p.name,p.price from product p where name like concat('%',#{nameaa},'%')
</select>
对应接口:
List<Product> productList();
List<Product> getProductsLikeName(String name);
采用if:如果没有传入Product对象就查询所有,传入了对象就根据product.name的值进行模糊查询,方便太多了。
<select id="list" resultType="Product" parameterType="Product">
select p.id,p.name,p.price from product p
<if test="name!=null">
where name like concat('%',#{name},'%')
</if>
</select>
对应接口:
List<Product> list();
List<Product> list(Product product);
二、where
如果有多个if来判断,前一个if不成立,可能就会出现多出一个and的错误情况。
where>标签会进行自动判断
如果任何条件都不成立,那么就在sql语句里就不会出现where关键字
如果有任何条件成立,会自动去掉多出来的 and 或者 or。
例如:除了根据name模糊查询,再加一个价格的筛选。
(如果不用where只用两个if,
假设name没有传值,那么sql语句就会变成 select p.id,p.name,p.price from product p and price>#{price}
这显然会报错。
)
<select id="list" resultType="Product" parameterType="Product">
select p.id,p.name,p.price from product p
<where>
<if test="name!=null">
and name like concat('%',#{name},'%')
</if>
<if test="price!=null">
and price>#{price}
</if>
</where>
</select>
三、set
在update语句里也会碰到多个字段相关的问题。 在这种情况下,就可以使用set标签:
name或者price有值的时候才进行sql拼接。
<update id="updateProduct" parameterType="Product" >
update product
<set>
<if test="name!=null">name=#{name},</if>
<if test="price!=null">price=#{price}</if>
</set>
where id=#{id}
</update>
四、trim
如果 where 元素没有按正常套路出牌,我们可以通过自定义 trim 元素来定制 where 元素的功能。比如,和 where 元素等价的自定义 trim 元素为:
prefixOverrides 属性会忽略通过管道分隔的文本序列(注意此例中的空格也是必要的)。它的作用是移除所有指定在 prefixOverrides 属性中的内容,并且插入 prefix 属性中指定的内容。
<trim prefix="WHERE" prefixOverrides="AND |OR ">
...
</trim>
例子:这里把<where>改为了<trim prefix="WHERE" prefixOverrides="AND |OR ">。
<select id="list" resultType="Product" parameterType="Product">
select p.id,p.name,p.price from product p
<trim prefix="WHERE" prefixOverrides="AND |OR ">
<if test="name!=null">
and name like concat('%',#{name},'%')
</if>
<if test="price!=null">
and price>#{price}
</if>
</trim>
</select>
例子:<set>改为了<trim prefix="SET" suffixOverrides=",">。
特别注意:我看的文档中提示出如果最后一个if不成立,删去的是后缀值,同时添加了前缀值。那么sql语句的结尾就会多出一个逗号。
<update id="updateProduct" parameterType="Product" >
update product
<trim prefix="SET" suffixOverrides=",">
<if test="name!=null">name=#{name},</if>
<if test="price!=null">price=#{price}</if>
</trim>
where id=#{id}
</update>
五、choose, when, otherwise
有时我们不想应用到所有的条件语句,而只想从中择其一项。针对这种情况,MyBatis 提供了 choose 元素,它有点像 Java 中的 switch 语句。
例子:如果传入的Product对象没有设置name和price的值,那么就执行查询id大于1的记录,如果name或price有值,那么就查询对应的,并且不执行<otherwise>中的语句。 非常的像switch语句。
<select id="list1" resultType="Product">
SELECT p.id,p.name,p.price FROM product p
<where>
<choose>
<when test="name != null">
and name like concat('%',#{name},'%')
</when>
<when test="price !=null and price != 0">
and price > #{price}
</when>
<otherwise>
and id >1
</otherwise>
</choose>
</where>
</select>
六、foreach
foreach标签通常用于in 这样的语法里。
例子:查询id为1和4的记录。
<select id="list3" resultType="Product">
SELECT p.id,p.name,p.price FROM product p
WHERE ID in
<foreach item="item" index="index" collection="list"
open="(" separator="," close=")">
#{item}
</foreach>
</select>
七、bind
bind 元素可以从 OGNL 表达式中创建一个变量并将其绑定到上下文。
<!-- 本来的模糊查询方式 -->
<!-- <select id="list4" resultType="Product"> -->
<!-- select p.id,p.name,p.price from product p where name like concat('%',#{0},'%') -->
<!-- </select> -->
<select id="list4" resultType="Product">
<bind name="likename" value="'%' + name + '%'" />
select p.id,p.name,p.price from product p where name like #{likename}
</select>
引用书籍中的话:
bind取代模糊查询的好处是提高了代码的可移植性。
在进行模糊查询时,如果是MySQL数据库,常常用到的是一个concat,它用'%'和参数相连。然而在Oracle数据库则没有,Oracle数据库用连接符号”||“。 当我们有了bind元素,就不必使用数据库语言,而是使用MyBatis的动态SQL即可完成。
所以无论是MySQL还是Oracle都可以使用这样的语句,从而提高了代码的可移植性。