Mybatis学习笔记(6)-动态SQL

2,354 阅读3分钟

MyBatis学习笔记(1)—使用篇

MyBatis学习笔记(2)—映射关系篇

MyBatis学习笔记(3)—高级映射之一对一映射

Mybatis学习笔记(4)-高级映射之一对多映射

Mybatis学习笔记(5)-高级映射之多对多映射

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,常用的元素也就这些了。