1. 程式人生 > 資料庫 >【MyBatis】MyBatis 動態 SQL

【MyBatis】MyBatis 動態 SQL

MyBatis 動態SQL

if

可以根據實體類的不同取值,使用不同的 SQL 語句來進行查詢。

使用動態 SQL 最常見情景是根據條件包含 where 子句的一部分。

持久層 DAO 介面:

public interface UserDAO {
    /**
     * 根據使用者資訊,查詢使用者列表
     * @param user
     * @return
     */
    List<User> findByUser(User user);
}

DAO 對映配置:

<mapper namespace="cn.parzulpan.dao.UserDAO">
    <select id="findByUser" resultType="User" parameterType="User">
        select * from user where 1 = 1
        <if test="username != null and username != ''">
            and username like #{username}
        </if>
        <if test="address != null">
            and address like #{address}
        </if>
    </select>

</mapper>

測試:

@Test
public void findByUserTest() {
    User user = new User();
    user.setUsername("%Tim%");
//        user.setAddress("%北京%");
    List<User> users = userDAO.findByUser(user);
    for (User u : users) {
        System.out.println(u);
    }
}

choose、when、otherwise

有時候,如果不想使用所有的條件,而只是想從多個條件中選擇一個使用。針對這種情況,MyBatis 提供了 choose

元素,它有點像 Java 中的 switch 語句。

持久層 DAO 介面:

public interface UserDAO {
    /***
     * 根據使用者資訊,查詢使用者列表,提供預設情況
     * @param user
     * @return
     */
    List<User> findByUserDefault(User user);
}

DAO 對映配置:

<mapper namespace="cn.parzulpan.dao.UserDAO">
    <select id="findByUserDefault" resultType="User" parameterType="User">
        select * from user where 1 = 1
        <choose>
            <when test="username !=null and username != ''">
                and username like #{username}
            </when>
            <when test="address != null">
                and address like #{address}
            </when>
            <otherwise>
                and id > 50
            </otherwise>
        </choose>
    </select>

</mapper>

測試:

@Test
public void findByUserDefaultTest() {
    User user = new User();
//        user.setUsername("%Tim%");
    List<User> users = userDAO.findByUserDefault(user);
    for (User u : users) {
        System.out.println(u);
    }
}

trim、where、set

為了去掉上面的 where 1 = 1 恆成立語句,可以使用 where 元素,where 元素只會在子元素返回任何內容的情況下才插入 “WHERE” 子句。而且,若子句的開頭為 “AND” 或 “OR”,where 元素也會將它們去除。

持久層 DAO 介面:

public interface UserDAO {
    /**
     * 根據使用者資訊,查詢使用者列表,使用 Where
     * @param user
     * @return
     */
    List<User> findByUserWhere(User user);
}

DAO 對映配置:

<mapper namespace="cn.parzulpan.dao.UserDAO">
    select * from user
    <where>
        <if test="username != null and username != ''">
            and username like #{username}
        </if>
        <if test="address != null">
            and address like #{address}
        </if>
    </where>
</mapper>

測試:

@Test
    public void findByUserWhereTest() {
        User user = new User();
//        user.setUsername("%Tim%");
        List<User> users = userDAO.findByUserWhere(user);
        for (User u : users) {
            System.out.println(u);
        }
    }

也可以通過自定義 trim 元素來定製 where 元素的功能。比如,和 where 元素等價的自定義 trim 元素為:

<trim prefix="WHERE" prefixOverrides="AND |OR ">
  ...
</trim>

prefixOverrides 屬性會忽略通過管道符分隔的文字序列,上述例子會移除所有 prefixOverrides 屬性中指定的內容,並且插入 prefix 屬性中指定的內容。

set 元素可以用於動態包含需要更新的列,忽略其它不更新的列,通常用於動態更新語句。

<mapper namespace="cn.parzulpan.dao.UserDAO">
    update user
    <set>
        <if test="username != null and username != ''">
            username = #{username},
        </if>
        <if test="address != null">
            address = #{address},
        </if>
    </set>
    where id = #{id}
</mapper>

和 set 元素等價的自定義 trim 元素為:

<trim prefix="SET" suffixOverrides=",">
  ...
</trim>

foreach

動態 SQL 的另一個常見使用場景是對集合進行遍歷,尤其是在構建 IN 條件語句的時候。

持久層 DAO 介面:

public interface UserDAO {
     /**
     * 根據 id 集合查詢使用者
     * @param v
     * @return
     */
    List<User> findByIds(QueryV v);
}

DAO 對映配置:

<mapper namespace="cn.parzulpan.dao.UserDAO">
    <select id="findByIds" resultType="User" parameterType="QueryV">
        select * from user
        <where>
            <if test="ids != null and ids.size() > 0">
                <foreach collection="ids" open="id in (" close=")" item="uid" separator=",">
                    #{uid}
                </foreach>
            </if>
        </where>
    </select>
</mapper>

測試:

@Test
public void findByIdsTest() {
    List<Integer> ids = new ArrayList<>();
    ids.add(41);
    ids.add(42);
    ids.add(43);
    ids.add(50);
    ids.add(51);
    ids.add(60);
    QueryV queryV = new QueryV();
    queryV.setIds(ids);
    List<User> users = userDAO.findByIds(queryV);
    for (User u : users) {
        System.out.println(u);
    }
}

簡化編寫的 SQL 片段

Sql 中可將重複的 sql 提取出來,使用時用 include 引用即可,最終達到 sql 重用的目的。

定義程式碼片段:

<!-- 抽取重複的語句程式碼片段 -->
<sql id="defaultSql">
    select * from user
</sql>

引用程式碼片段:

<!-- 配置查詢所有操作 -->
<select id="findAll" resultType="user">
    <include refid="defaultSql"></include>
</select>

<!-- 根據 id 查詢 -->
<select id="findById" resultType="User" parameterType="int">
    <include refid="defaultSql"></include>
    where id = #{uid}
</select>

練習和總結