(一)电子钱包充值N元可以无限购买价值N元的商品而余额依然是N元

一、现象

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,更新成功

以上内容,全部抄袭。未得到任何授权,如有质疑,立刻删除。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。