MyBatis中不建議使用where 1=1原因詳解

前言

最近接手瞭一個老項目,“愉悅的心情”自然無以言表,做開發的朋友都懂,這裡就不多說瞭,都是淚…

接手老項目,自然是要先熟悉一下業務代碼,然而在翻閱 mapper 文件時,發現瞭一個比較詭異的事情。這裡給出簡化後的業務代碼:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.demo.mapper.UserMapper">
    <select id="list" resultType="com.example.demo.model.User">
        select * from user
        where 1=1
        <if test="name!=null">
            and name=#{name}
        </if>
        <if test="password!=null">
            and password=#{password}
        </if>
    </select>
</mapper>

機智的小夥伴可能已經看出瞭問題,在眾多 mapper 中發現瞭一個相同的想象,幾乎所有的 mapper 中都包含瞭一個無用的拼接 SQL:where 1=1。作為一個幾乎有代碼潔癖癥的人,自然是忍不住動手改造一番瞭。

錯誤的改造方式

既然是去掉 where 1=1,那最簡單的方式就是將它直接從代碼中刪除瞭,如下代碼所示:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.demo.mapper.UserMapper">
    <select id="list" resultType="com.example.demo.model.User">
        select * from user
            where
            <if test="name!=null">
                name=#{name}
            </if>
            <if test="password!=null">
                and password=#{password}
            </if>
    </select>
</mapper>

以上代碼刪除瞭 1=1,並且把第一個 name 查詢中的 and 去掉瞭,以防 SQL 查詢報錯。

但這樣就沒問題瞭嗎?我們直接來看結果,當包含參數 name 查詢時,結果如下:

一切順利成章,完美的一塌糊塗。

然而,當省略 name 參數時(因為 name 為非必要參數,所以可以省略),竟然引發瞭以下異常:

又或者隻有 password 查詢時,結果也是一樣:

都是報錯信息,那腫麼辦呢?難不成把 1=1 恢復回去?

正確的改進方式

其實不用,在 MyBatis 中早已經想到瞭這個問題,我們可以將 SQL 中的 where 關鍵字換成 MyBatis 中的 標簽,並且給每個 標簽內都加上 and 拼接符,這樣問題就解決瞭,如下代碼所示:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.demo.mapper.UserMapper">
    <select id="list" resultType="com.example.demo.model.User">
        select * from user
        <where>
            <if test="name!=null">
               and name=#{name}
            </if>
            <if test="password!=null">
                and password=#{password}
            </if>
        </where>
    </select>
</mapper>

代碼改造完成之後,接下來我們來測試一下所有的請求場景。

不傳任何參數的請求

此時我們可以不傳遞任何參數(查詢所有數據),如下圖所示:

生成的 SQL 語句如下:

傳遞 1 個參數的請求

也可以傳遞 1 個參數,根據 name 進行查詢,如下圖所示:

生成的 SQL 如下圖所示:

也可以隻根據 password 進行查詢,如下圖所示:

生成的 SQL 如下圖所示:

傳遞 2 個參數的請求

也可以根據 name 加 password 的方式進行聯合查詢,如下圖所示:

生成的 SQL 如下圖所示:

用法解析

我們驚喜的發現,在使用瞭 標簽之後,無論是任何查詢場景,傳一個或者傳多個參數,或者直接不傳遞任何參數,都可以輕松搞定。

首先, 標簽會判斷,如果沒有任何參數,則不會在 SQL 語句中拼接 where 查詢,反之才會拼接 where 查詢;其次在 查詢的 標簽中,每個 標簽都可以加 and 關鍵字,MyBatis 會自動將第一個條件前面的 and 關鍵字刪除掉,從而不會導致 SQL 語法錯誤,這一點官方文檔中也有說明,如下圖所示:

總結

在 MyBatis 中,建議盡量避免使用無意義的 SQL 拼接 where 1=1,我們可以使用 標簽來替代 where 1=1,這樣的寫既簡潔又優雅,何樂而不為呢?以上內容僅為個人觀點,更多關於MyBatis不建議用where 1=1的資料請關註WalkonNet其它相關文章!

推薦閱讀: