注意了!mybatis中<if>条件判断,遇到带数字单字符有坑!

mybatis判断条件<if>与单字符数字比较,会判断错误。大家是否踩过这个坑?

1.代码复现

先看这个例子:

//UserInfoTab 对象
@Data
public class UserInfoTab {
    private Integer id;

    private String userName;

    private String userId;
    ...
}

mybatis 查询

 <select id="selectByUserInfo" resultMap="BaseResultMap">
    select
    <include refid="Base_Column_List" />
    from user_info_tab a
    <where>
      <if test="userId == '1' ">
        and a.user_name = 'tianluoboy'
      </if>
      <if test="userId != '1' ">
        and a.user_name != 'tianluoboy'
      </if>
    </where>
  </select>

目前用户表的数据:

图片

现在我的单元测试查询是这样的:

    @Test
    void testQueryUserInfo(){
        List<UserInfoTab> userInfoTabList = userInfoTabDao.selectByUserInfo("1");
        if (CollectionUtils.isEmpty(userInfoTabList)) {
            userInfoTabList.forEach(System.out::println);
        }
    }

如果这个条件生效:

<if test="userId == '1' ">
        and a.user_name = 'tianluoboy'
</if>

我应该查到tianluoboy这条记录,但是事实查到的结果,却是:

图片

也就是说<if test="userId == '1' ">这个条件不生效。

2. 正确的使用方法

如果改成用双引号包着"1",或者用toString()转换一下,则是可以正确查出来的:

 <if test='userId == "1"'>
        and a.user_name = 'tianluoboy'
</if>

<if test="userId == '1'.toString()">
   and a.user_name = 'tianluoboy'
</if>

3. 原因解析

Mybatis 是使用OGNL表达式来解析的,'1'会解析为字符Character,一个字符Character和一个String 当然不相等,这就是为什么<if test="userId == '1' ">不生效。

图片

大家有兴趣可以去debug看看源码哈,这个类:

org.apache.ibatis.ognl.OgnlOps

关键方法是这个:

public static int compareWithConversion(Object v1, Object v2) {
        label75: {
            int result;
            if (v1 == v2) {
                result = 0;
            } else {
                int t1 = getNumericType(v1);
                int t2 = getNumericType(v2);
                int type = getNumericType(t1, t2, true);
                switch (type) {
                    case 6:
                        result = bigIntValue(v1).compareTo(bigIntValue(v2));
                        break;
                    case 7:
                    case 8:
                        break label75;
                    case 9:
                        result = bigDecValue(v1).compareTo(bigDecValue(v2));
                        break;
                    case 10:
                        if (t1 != 10 || t2 != 10) {
                            break label75;
                        }

                        if (v1 instanceof Comparable && v1.getClass().isAssignableFrom(v2.getClass())) {
                            result = ((Comparable)v1).compareTo(v2);
                            break;
                        }

                        if (!(v1 instanceof Enum) || !(v2 instanceof Enum) || v1.getClass() != v2.getClass() && ((Enum)v1).getDeclaringClass() != ((Enum)v2).getDeclaringClass()) {
                            throw new IllegalArgumentException("invalid comparison: " + v1.getClass().getName() + " and " + v2.getClass().getName());
                        }

                        result = ((Enum)v1).compareTo(v2);
                        break;
                    default:
                        long lv1 = longValue(v1);
                        long lv2 = longValue(v2);
                        return lv1 == lv2 ? 0 : (lv1 < lv2 ? -1 : 1);
                }
            }

            return result;
        }

        double dv1 = doubleValue(v1);
        double dv2 = doubleValue(v2);
        return dv1 == dv2 ? 0 : (dv1 < dv2 ? -1 : 1);
    }
<select id="selectPageWithParam" resultType="com.cmb.xft.ini.domain.pojo.InvoiceRiskAlarmResult"> select ira.id as id, ira.enterprise_id as enterprise_id, ira.alarm_date as alarm_date, ira.invoice_in_id as invoice_in_id, ira.alarm_info as alarm_info, i.invoice_code as invoice_code, i.invoice_number as invoice_number, i.electronic_invoice_number as electronic_invoice_number, i.issue_time as issue_time, i.invoice_type as invoice_type, i.sys_invoice_type as sys_invoice_type, i.invoice_status as invoice_status, i.buyer_company_name as buyer_company_name, i.buyer_taxpayer_id as buyer_taxpayer_id, i.seller_company_name as seller_company_name, i.seller_taxpayer_id as seller_taxpayer_id, i.tax_included_amount as tax_included_amount from invoice_in_risk_alarm ira left join invoice_in i on ira.invoice_in_id = i.id where ira.enterprise_id = #{enterpriseId} <if test="param.newestAlarmDateStart != null"> and ira.alarm_date >= #{param.newestAlarmDateStart} </if> <if test="param.newestAlarmDateEnd != null"> and ira.alarm_date <= #{param.newestAlarmDateEnd} </if> <if test="param.alarmInfo != null and param.alarmInfo.size() != 0"> and <foreach collection="param.alarmInfo" item="alarmInfo" open="(" separator="or" close=")"> ira.alarm_info like concat('%', #{alarmInfo}, '%') </foreach> </if> <if test="param.sysInvoiceTypes != null and param.sysInvoiceTypes.size() != 0"> and i.sys_invoice_type in <foreach collection="param.sysInvoiceTypes" item="invoiceType" open="(" separator="," close=")"> #{invoiceType} </foreach> </if> <if test="param.invoiceStatuses != null and param.invoiceStatuses.size() != 0"> and i.invoice_status in <foreach collection="param.invoiceStatuses" item="invoiceStatus" open="(" separator="," close=")"> #{invoiceStatus} </foreach> </if> <if test="param.sellerTaxpayerId != null and param.sellerTaxpayerId != ''"> and i.seller_taxpayer_id like concat('%', #{param.sellerTaxpayerId}, '%') </if> <if test="param.sellerCompanyName != null and param.sellerCompanyName != ''"> and i.seller_company_name like concat('%', #{param.sellerCompanyName}, '%') </if> <if test="param.invoiceNumber != null and param.invoiceNumber != ''"> and i.invoice_number like concat('%', #{param.invoiceNumber}, '%') </if> <if test="param.invoiceCodePattern != null and param.invoiceCodePattern != ''"> and i.invoice_code like concat('%', #{param.invoiceCodePattern}, '%') </if> <if test="param.electronicInvoiceNumber != null and param.electronicInvoiceNumber != ''"> and i.electronic_invoice_number like concat('%', #{param.electronicInvoiceNumber}, '%') </if> <if test="param.issueTimeStart != null"> and i.issue_time >= #{param.issueTimeStart} </if> <if test="param.issueTimeEnd != null"> and i.issue_time < #{param.issueTimeEnd} </if> <if test="param.taxIncludedAmountStart != null"> and i.tax_included_amount >= #{param.taxIncludedAmountStart} </if> <if test="param.taxIncludedAmountTo != null"> and i.tax_included_amount <= #{param.taxIncludedAmountTo} </if> <choose> <when test="param.orderQueryParam != null"> order by <if test="param.orderQueryParam.field != null and param.orderQueryParam.field != ''"> ${param.orderQueryParam.field} ${param.orderQueryParam.method}, </if> ira.update_time desc </when> <otherwise> order by ira.update_time desc, i.invoice_number desc </otherwise> </choose> </select> 这一段有什么错误吗
06-18
UPDATE t_card_info <trim prefix="SET" suffixOverrides=","> <trim prefix="flows_end_time = CASE" suffix="END,"> <foreach collection="list" item="item"> <if test="item.flowsEndTime != null"> WHEN card_id = #{item.cardId} THEN #{item.flowsEndTime} </if> </foreach> </trim> <trim prefix="flows_yesterday_used = CASE" suffix="END,"> <foreach collection="list" item="item"> <if test="item.flowsYesterdayUsed != null"> WHEN card_id = #{item.cardId} THEN #{item.flowsYesterdayUsed} </if> </foreach> </trim> <trim prefix="virtual_used = CASE" suffix="END,"> <foreach collection="list" item="item"> <if test="item.virtualUsed != null"> WHEN card_id = #{item.cardId} THEN #{item.virtualUsed} </if> </foreach> </trim> <trim prefix="virtual_rest = CASE" suffix="END,"> <foreach collection="list" item="item"> <if test="item.virtualRest != null"> WHEN card_id = #{item.cardId} THEN #{item.virtualRest} </if> </foreach> </trim> <trim prefix="virtual_yesterday_used = CASE" suffix="END,"> <foreach collection="list" item="item"> <if test="item.virtualYesterdayUsed != null"> WHEN card_id = #{item.cardId} THEN #{item.virtualYesterdayUsed} </if> </foreach> </trim> <trim prefix="flows_update_time = CASE" suffix="END,"> <foreach collection="list" item="item"> <if test="item.flowsUpdateTime != null"> WHEN card_id = #{item.cardId} THEN #{item.flowsUpdateTime} </if> </foreach> </trim> <trim prefix="real_name_status = CASE" suffix="END,"> <foreach collection="list" item="item"> <if test="item.realNameStatus != null and item.realNameStatus != ''"> WHEN card_id = #{item.cardId} THEN #{item.realNameStatus} </if> </foreach> </trim> <trim prefix="status = CASE" suffix="END,"> <foreach collection="list" item="item"> <if test="item.status != null and item.status != -1"> WHEN card_id = #{item.cardId} THEN #{item.status} </if> </foreach> </trim> </trim> WHERE card_id IN <foreach collection="list" item="item" open="(" close=")" separator=","> #{item.cardId} </foreach> <if test="item.realNameStatus != null and item.realNameStatus != ''"> 这个 <if test="item.status != null and item.status != -1"> 就算等与null或者空字符串或者-1还是进来了
06-07
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值