首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計疑難解答

MyBatis foreach 處理空 List 參數:避免 SQL 語法錯誤的最佳實踐

     編輯:程式設計疑難解答

問題場景

MyBatis 中使用 <foreach> 遍歷 List 參數構建 IN 查詢時,若 List 為空,生成的 SQL 會出現 IN () 導致語法錯誤。

錯誤 SQL 示例

SELECT * FROM table WHERE id IN ()  -- 語法錯誤!

解決方案對比

方案一:條件判斷 + 恆假條件(推薦,通用性強)

<where>
    <if test="list != null and list.size() > 0">
        AND column_name IN
        <foreach collection="list" item="item" open="(" separator="," close=")">
            #{item}
        </foreach>
    </if>
    <if test="list == null or list.size() == 0">
        AND 1 = 0  -- 恆假條件,不影響查詢邏輯
    </if>
</where>

方案二:使用 bind 標簽預處理(MyBatis 3.4+)

<bind name="safeList" value="@java.util.Collections@emptyList()" />
<!-- 或在 Java 代碼中保證 list 不為 null -->
<where>
    <if test="list != null and list.size() > 0">
        AND column_name IN
        <foreach collection="list" item="item" open="(" separator="," close=")">
            #{item}
        </foreach>
    </if>
</where>

方案三:原提問者的「取巧」做法(不推薦生產環境)

<if test="list != null and list.size() > 0">
    AND column_name IN
    <foreach collection="list" item="item" open="(" separator="," close=")">
        #{item}
    </foreach>
</if>
<if test="list == null or list.size() == 0">
    AND column_name = 'IMPOSSIBLE_VALUE_THAT_NEVER_EXISTS'
</if>

⚠️ 缺點:硬編碼魔法值,若業務數據真包含該值會產生邏輯錯誤。

最佳實踐建議

1. Java 層保證參數非空

// Service 層
List<Long> ids = getIds();
if (ids == null) {
    ids = Collections.emptyList(); // 返回空列表而非 null
}
mapper.selectByIds(ids);

2. Mapper 統一使用 <where> 標簽

<select id="selectByIds" resultType="Entity">
    SELECT * FROM table
    <where>
        <if test="ids != null and ids.size() > 0">
            AND id IN
            <foreach collection="ids" item="id" open="(" separator="," close=")">
                #{id}
            </foreach>
        </if>
    </where>
</select>

<where> 會自動處理 AND/OR 前綴,若條件全不滿足則不生成 WHERE 子句。

3. 複雜查詢考慮動態 SQL 封裝

<sql id="idInClause">
    <if test="ids != null and ids.size() > 0">
        AND id IN
        <foreach collection="ids" item="id" open="(" separator="," close=")">
            #{id}
        </foreach>
    </if>
</sql>

<select id="selectByIds">
    SELECT * FROM table
    <where>
        <include refid="idInClause" />
    </where>
</select>

總結

  • ✅ **首選**:Java 層保證非空 + Mapper 用 <where> + <if test="size > 0"
  • ✅ **備選**:<if> 分支覆蓋空列表情況,使用恆假條件 1=0
  • ❌ **避免**:硬編碼不可能值、依賴數據庫特定行為
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved