Các lỗi phổ biến khi sử dụng điều kiện if-test trong MyBatis

Trong MyBatis, việc sử dụng điều kiện <if test="..."> có thể dẫn đến lỗi logic không mong muốn do cách OGNL xử lý biểu thức. Ví dụ với điều kiện deliveryType == '1' sẽ không hoạt động đúng vì OGNL interpret ký tự đơn trong single quote thành kiểu char. Hãy sửa thành <if test='deliveryType == "1"'> hoặc <if test="deliveryType == '1'.toString() ">

<insert id="insertDelivery" parameterType="com.example.model.DeliveryConfig">
    INSERT INTO delivery_preferences
    <trim prefix="(" suffix=")" suffixOverrides=",">
        <if test='deliveryType == "1" and workday != null'> 
            WORKDAY,
        </if>
    </trim>
    <trim prefix="VALUES (" suffix=")" suffixOverrides=",">
        <if test='deliveryType == "1" and workday != null'> 
            #{workday},
        </if>
    </trim>
</insert>
Khi deliveryType == "1" bị lỗi, hệ thống sẽ bỏ qua khối SQL bên trong mà không báo lỗi. Điều này xảy ra do OGNL - thư viện xử lý biểu thức của MyBatis, interpret '1' (single quote) thành kiểu char, trong khi deliveryType là kiểu String. Hai kiểu dữ liệu này không thể so sánh trực tiếp trong Java.
Ngoài ra, với kiểu dữ liệu số nguyên như Integer status:

private Integer status; // Có thể nhận giá trị 0, 1, 2, 3
Đoạn XML sau sẽ không hoạt động đúng khi status = 0:

<if test="status != null and status !=''"> 
    AND status = #{status}
</if>
Lỗi này xảy ra vì OGNL interpret giá trị 0 thành chuỗi trống. Để khắc phục, chỉ cần kiểm tra status != null:

<if test="status != null"> 
    AND status = #{status}
</if>
Phân tích từ lớp ExpressionEvaluator trong MyBatis cho thấy:

public class ExpressionEvaluator {
    public boolean evaluateBoolean(String expression, Object parameterObject) {
        Object value = OgnlCache.getValue(expression, parameterObject);
        if (value instanceof Boolean) return (Boolean) value;
        if (value instanceof Number) return !new BigDecimal(value.toString()).equals(BigDecimal.ZERO);
        return value != null;
    }
}
Theo tài liệu chính thức của OGNL, các giá trị kiểu Number bằng 0 sẽ được coi là false. Điều này giải thích tại sao biểu thức status != null and status != '' trả về false khi status = 0.
Một lỗi phổ biến khác xảy ra khi so sánh chuỗi với ký tự đơn:

String channel = "MOBILE";
<if test="channel == 'M' and channel != null"> 
    -- Logic xử lý
</if>
Biểu thức này sẽ không hoạt động vì OGNL interpret 'M' thành kiểu char. Hãy sửa thành:

<if test='channel == "M" and channel != null'>
Tóm lại:
  • Luôn dùng double quote cho chuỗi trong biểu thức OGNL
  • Không kiểm tra != '' với kiểu dữ liệu không phải String
  • Hiểu rõ cách OGNL xử lý các kiểu dữ liệu khác nhau

Thẻ: mybatis ognl Java dynamic-sql

Đăng vào ngày 13 tháng 6 lúc 20:27