Mybatis一项强大的功能就是动态SQL,你可以使用动态SQL为SQL语句带上一些逻辑,免除使用JDBC时拼装SQL的痛苦,下面我们来看一些最常见的应用。
if (判断元素)
我们在代码中时常使用if语句来做判断,而在Mybatis里,也可以使用if元素,下面我们通过实例来看一个简单的用法:
<select id="findProductList" parameterType="com.shuqing28.pojo.Products"
resultType="com.shuqing28.pojo.Products">
SELECT * FROM products
WHERE 1=1
<if test="prodName!=null and prodName!=''">
AND prod_name like '%${prodName}%'
</if>
</select>
这里我们使用一个if语句来探测prodName是否为空,如果不为空就加上prod_name的模糊匹配,如果参数为空就不构造这个条件。 在这里我们看到有个WHERE 1=1
其实这里是为了防止后面条件一旦为真,那么不加上WHERE 1=1
的话,查询语句就变成了SELECT * FROM products AND prod_name like '%${prodName}%'
,直接接上了AND,有问题了。
其实还有几种方法可以让我们不使用WHERE 1=1
where, trim, set
针对上面的 WHERE 1=1
我们可以使用WHERE元素替代:
<select id="findProductList" parameterType="com.shuqing28.pojo.Products"
resultType="com.shuqing28.pojo.Products">
SELECT * FROM products
<where>
<if test="prodName!=null and prodName!=''">
AND prod_name like '%${prodName}%'
</if>
</where>
</select>
where元素里面的if为真时,它才会把WHERE子句加进去,而且会自动调整AND是否存在。
也可以使用trim
来调整格式:
<select id="findProductList" parameterType="com.shuqing28.pojo.Products"
resultType="com.shuqing28.pojo.Products">
SELECT * FROM products
<trim prefix="WHERE" prefixOverrides="AND">
<if test="prodName!=null and prodName!=''">
AND prod_name like '%${prodName}%'
</if>
</trim>
</select>
在这里prefix
代表前缀,prefixoverride
则会去掉第一个AND
,所以最后的效果和where元素是一样的。
而set元素则是应用于更新,加入我们要更新某个字段:
<update id="updateProduct" parameterType="com.shuqing28.pojo.Products">
UPDATE products
<set>
<if test="prodName!=null and prodName!=''">
AND prod_name like '%${prodName}%'
</if>
</set>
WHERE prod_id=#{prodId}
</update>
这里用set包裹,也就是如果if元素判断为真,就会自动添加SET
子句
UPDATE products SET prod_name like '%${prodName}% WHERE prod_id=#{prodId}
当然也可以使用trim元素:
<trim prefix="SET" suffixOverride=",">...</trim>
只要把前缀换成SET,suffixOverride则会自动把最后的不需要的,
去掉,当然set
自带去最后逗号的功能。
foreach
显然foreach
是一个循环语句,它的作用就是遍历集合,如果传入的是一个List、Set接口的集合,那么它就可以大展身手了。 假如有以下的查询:
SELECT * FROM products WHERE prod_id IN ("ANV01", "ANV02", "ANV03");
那么我们可以把3个参数封装到一个List中,然后用foreach
语句遍历取出:
<select id="findProductListByProdId" parameterType="java.util.List"
resultType="com.shuqing28.pojo.Products">
SELECT * FROM products
WHERE prod_id IN
<foreach item="prod_id" index="index" collection="list" open="(" separator="," close=")">
#{prod_id}
</foreach>
</select>
再看看使用时是怎么操作的:
@Test
public void findProductListByProdId(){
SqlSession sqlSession = sqlSessionFactory.openSession();
try {
OrdersDao ordersDao = sqlSession.getMapper(OrdersDao.class);
List<String> prodList = new ArrayList<String>();
prodList.add("ANV01");
prodList.add("ANV02");
prodList.add("ANV03");
List<Products> productList = ordersDao.findProductListByProdId(prodList);
System.out.println(productList);
} finally {
sqlSession.close();
}
}
构造出查询参数,直接传入list即可。
bind
其它的动态SQL参数包括前面一直包含的test
,用于在条件判断元素中测试真假,还有个bind
元素,用于定义一个上下文变量,比如我们第一个例子中的%${prodName}%
,我们也可以用bind
事先定义好:
<select id="findProductList" parameterType="com.shuqing28.pojo.Products"
resultType="com.shuqing28.pojo.Products">
<bind name="pattern" value="'%' + _parameter + '%'"/>
SELECT * FROM products
WHERE 1=1
<if test="prodName!=null and prodName!=''">
AND prod_name like #{pattern}'
</if>
</select>
上例中我们预先定义好pattern,使用时就可以直接拿来用了,对于多处使用的变量适合这样操作,这里的_parameter
代表传入的参数,它和通配符结合后,赋给了pattern
。
关于动态SQL,常用的元素也就这些了。