发表文章

[最新] 项目中,mybatis 有时 update 语句执行无效的解决

qq34963080 2月前 7

公司测试人员在测试的时候发现,在积分系统,消费产生了积分,有时候,却不能加到用户累计积分上去。

明明积分流水记录跟用户积分的增加在一个事务当中的。积分流水记录生成成功,偏偏用户积分没有加上去?奇了怪了。加积分的代码是:tMemberPointMapper.updateByPrimaryKeySelective(tMemberPoint);

然后在相应的位置,加了日志,记录更新语句前后的对比。

测试人员再次发现问题时查看了日志,日志显示更新语句执行后的对象确实是有累加过积分的。为什么数据库表中的值就是没变呢?

于是百度啊,这种情况百度的结果比较少,有的说是mybatis的版本的问题?个人感觉不太可能,因为这个mybatis版本在很多项目是使用,都没出过问题。事务也是测试过,有异常能够回滚。

后来冷静下来想了想出现问题的时机。测试人员在消费操作过后,会立刻点查看用户积分的界面。这时会调获取用户积分信息的接口。因为这个接口,不仅仅是查询,因为等积维持机制(过一定的周期,要扣掉一部分积分), 它在查询前,对用户积分有修改的操作。所在,查询用户积分的接口,也处在非只读的事务中。

当两个对同条用户积分记录操作的事务同时执务(InnoDb的行级锁,排它锁),由于,mysql的默认隔离级别是repeatable-read,事务A和事务B,读到数据为a,后事务B修改了数据为b,提交了,而事务A再执行修改操作,又会把数据b修改为数据a。这就出现了,题中所述的,偶尔出现update语句执行无效的假象。

解决办法:悲观锁 在查询语句后加 for update ,锁住事务中,查询用户积分的语句。 

 <select id="selectByExample" resultMap="BaseResultMap" parameterType="com.ice.pojo.f3.TMemberPointExample" >
    select
    <if test="distinct" >
      distinct
    </if>
    <include refid="Base_Column_List" />
    from t_member_point
    <if test="_parameter != null" >
      <include refid="Example_Where_Clause" />
    </if>
    <if test="orderByClause != null" >
      order by ${orderByClause}
    </if>
    for update
  </select>

 

相关推荐
最新评论 (0)
返回
发表文章
qq34963080
文章数
4
评论数
0
注册排名
1314860