首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

MyBatis 中 OGNL 表達式使用完全指南:動態 SQL 與參數綁定實戰

     編輯:Java 相關知識

OGNL 在 MyBatis 中的兩大應用場景

  1. 動態 SQL 表達式:``、`` 中的條件判斷
  2. ${param} 參數替換:SQL 片段直接拼接(非預編譯,防注入需自行處理)

MyBatis 常用 OGNL 表達式速查表

類別表達式說明
邏輯運算e1 or e2 / e1 and e2邏輯或/與
e1 == e2 / e1 eq e2等於
e1 != e2 / e1 neq e2不等於
e1 lt e2小於 (<)
e1 lte e2小於等於 (<=)
e1 gt e2 / e1 gte e2大於 (>) / 大於等於 (>=)
集合操作e1 in e2包含於
e1 not in e2不包含於
e1[ e2 ]按索引/鍵取值 (List/Map/數組)
算術運算e1 + e2加/字符串拼接
e1 - e2 / e1 * e2 / e1 / e2 / e1 % e2減/乘/除/模
方法/屬性訪問e.method(args)調用對象方法
e.property獲取對象屬性 (走 getter)
靜態調用@class@method(args)調用類靜態方法
@class@field獲取類靜態字段
!e / not e邏輯非

場景一:動態 SQL 中的 test 條件

1. 基礎 LIKE 查詢


<select id="selectByName" resultType="Country">
    SELECT * FROM country
    <where>
        <if test="name != null and name != ''">
            name LIKE CONCAT('%', #{name}, '%')
        </if>
    </where>
</select>

`test` 內容由 OGNL 計算,結果為 boolean 決定 SQL 片段是否生效。

2. <bind> 變量綁定(推薦防注入)


<select id="selectByName" resultType="Country">
    SELECT * FROM country
    <bind name="nameLike" value="'%' + name + '%'"/>
    <where>
        <if test="name != null and name != ''">
            name LIKE #{nameLike}
        </if>
    </where>
</select>

value 為 OGNL 表達式,結果綁定為 `nameLike` 變量,後續用 `#{nameLike}` 安全引用。

3. 調用靜態方法生成 UUID(通用 Mapper 實戰)


<bind name="uuid" value='@java.util.UUID@randomUUID().toString().replace("-", "")' />
<insert id="insert">
    INSERT INTO t_user (id, name) VALUES (#{uuid}, #{name})
</insert>

⚠️ **注意**:`` 調用靜態方法無法回寫屬性值,僅適用於插入前生成值場景。

場景二:${param} 直接拼接

簡化 LIKE 查詢


<if test="name != null and name != ''">
    name LIKE '${'%' + name + '%'}'
</if>

**關鍵區別**:

  • `${'%' + name + '%'}`:OGNL 計算完整字符串 → 直接替換 SQL 文本
  • `%${name}%`:MyBatis 先替換 `${name}` → 再拼接 `%`,處理順序不同,易產生語法錯誤

進階實戰:動態分表功能實現

1. 定義標識接口


public interface IDynamicTableName {
    String getDynamicTableName(); // 返回動態表名,null/空則用默認表
}

2. 實體類實現接口


public class OrderQuery implements IDynamicTableName {
    private String dynamicTableName;
    // getter/setter
    @Override
    public String getDynamicTableName() { return dynamicTableName; }
}

3. 工具類判斷參數類型


public class OGNLUtil {
    public static boolean isDynamicParameter(Object parameter) {
        return parameter instanceof IDynamicTableName;
    }
    public static boolean isNotDynamicParameter(Object parameter) {
        return !isDynamicParameter(parameter);
    }
}

4. XML 動態表名切換


<select id="selectOrders" resultType="Order">
    SELECT * FROM 
    <if test="@tk.mybatis.mapper.util.OGNLUtil@isDynamicParameter(_parameter) 
             and dynamicTableName != null and dynamicTableName != ''">
        ${dynamicTableName}  <!-- 直接拼接表名,無法用 #{} -->
    </if>
    <if test="@tk.mybatis.mapper.util.OGNLUtil@isNotDynamicParameter(_parameter) 
             or dynamicTableName == null or dynamicTableName == ''">
        default_order_table
    </if>
    <where>
        <!-- 其他條件 -->
    </where>
</select>

關鍵點**:

  • `_parameter`:MyBatis 內置變量,代表 Mapper 方法的單個參數對象
  • `dynamicTableName`:MyBatis 自動調用 `getDynamicTableName()` getter 獲取值
  • 表名**必須用 `${}` 直接拼接**,`#{}` 會當作參數預編譯導致語法錯誤

學習建議

  1. **動手實驗**:編寫測試用例覆蓋各種 OGNL 表達式
  2. **啟用日誌**:`log4j.logger.org.apache.ibatis=DEBUG` 觀察 SQL 生成過程
  3. **安全第一**:優先用 `#{}` + ``,僅在表名/列名/排序等無法預編譯場景用 `${}`
  4. **源碼閱讀**:`OgnlCache`、`ExpressionEvaluator`、`DynamicSqlSource` 理解解析流程
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved