一、现象
1)钱包余额1分钱时,买一件一分钱商品,小程序订单显示电子钱包支付了一分钱,但没有看到微信支付信息,零钱也没扣。相当于免费领
2)余额7分钱时,买一件一分钱商品,零钱扣费正常。
3)余额7分钱时,买一件一毛钱商品,零钱扣费正常。
二、问题分析
一行Mybatis代码导致:
balance是钱包余额,在这种情况下单元测试:支付前balance是1分钱,支付1分钱后,balance依然1。so:update没有执行:
然而我删除 balance != ''的代码变为如下,balance被更新为0
<if test="balance != null">
BALANCE = #{balance,jdbcType=BIGINT},
</if>
mybatis会将Integer类型的0被识别成空字符串!如果java代码需要往mybatis传递整数0,那么需要使用增强版的判断。例如:
<if test="status != null and status !='' or status==0">
and status=#{status,jdbcType=INTEGER}
</if>原理看源码
三、MyBatis源码解析
Mybatis的核心源码中有一个接口
核心方法getBoundSql:构建sql,保存经过参数解析、判断解析完成sql语句。最常用sqlSource的实现类是DynamicSqlSource.class
核心方法是调用了rootSqlNode.apply(context);:执行一个递归的调用
通过不同的实现类执行不同的标签,每一次apply是完成了我们<>一次标签中的sql创建,计算出标签中的那一段sql,mybatis通过不停的递归调用,来为我们完成了整个sql的拼接。
这个方法有很多的实现类,
demo中的的实现类是IfSqlNode
if (evaluator.evaluateBoolean(test, context.getBindings())) false直接返回,否则继续递归解析IF标签以下的标签,并且返回true。
关键点就在于OgnlCache.getValue中调用了Ognl.getValue,恍然大悟,mybatis是使用OGNL表达式来解析。
四、Mybatis源码debug
第一种情况如下的debug:
<if test="balance != null" and balance != ''>
我们直接在org.apache.ibatis.scripting.xmltags.OgnlCache处debug
然而在org.apache.ibatis.scripting.xmltags.ExpressionEvaluator真正获取的时候,则直接返回了false,直接导致了更新操作无法执行
<if test="balance != null" and balance != ''>
BALANCE = #{balance,jdbcType=BIGINT},
</if>
但是如果按照上文的修复措施处理以后,该方法返回true,更新成功
以上内容,全部抄袭。未得到任何授权,如有质疑,立刻删除。