MyBatis 中使用 <foreach> 遍歷 List 參數構建 IN 查詢時,若 List 為空,生成的 SQL 會出現 IN () 導致語法錯誤。
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 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>
⚠️ 缺點:硬編碼魔法值,若業務數據真包含該值會產生邏輯錯誤。
// Service 層
List<Long> ids = getIds();
if (ids == null) {
ids = Collections.emptyList(); // 返回空列表而非 null
}
mapper.selectByIds(ids);
<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 子句。
<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>
<where> + <if test="size > 0"<if> 分支覆蓋空列表情況,使用恆假條件 1=0