美文网首页
Mybatis Update没执行

Mybatis Update没执行

作者: 风吟空城 | 来源:发表于2018-11-13 17:53 被阅读0次

    引言

    某项目采用“同步请求+异步回调”的方式,实现了用户账户信息的更新(余额、冻结金额等)。有时调用账户更新方法时,会出现数据库中账户信息没有修改的情况。但是,查看日志的时候,方法确实又执行了。结果就是导致用户账户信息异常。

    思路

    思路1

    代码中出现了以下两种情形:

    • 没有添加事务;
    • 事务等待锁的时间过长被杀死;

    在经查看日志信息和其他级联数据时,发现都不是以上两种情形。

    思路2

    2个事务同时执行,前者事务被后者事务覆盖,出现了脏写。

    经过仔细查看代码,发现是2个功能事务同时执行,其中一方加了悲观锁,一方没有加锁。下面通过一个简单的示例,描述下问题是如何产生的。

    示例:用户账户冻结金额

    方法一

    public boolean changeAccount(Long id){
        //...省略部分代码
        //数据库加悲观锁 frozen = 100
        Account account = accountDao.getByIdForUpdate(id);
        account.setFrozen(account.getFrozen() + 100);
        //frozen = 200
        accountDao.modify(account);
        //...省略部分代码
    }
    

    方法二

    public Account getByOwnerId(Long ownerId , HttpServletRequest request) {
        //...省略部分代码
        //更新余额 frozen = 100               
        account.setBalance(Double.valueOf(results.get("balance").toString()));
        //frozen = 100
        accountDao.modify(account);
        //...省略部分代码   
    }
    

    modify()是一个全量更新的方法

    方法二在获取到account(frozen = 100)时,方法一(frozen = 100)将表锁住,此时,方法二无法继续进行下去,只能等待方法一执行完。方法一在更新完frozen信息后,释放锁,此时frozen = 200。方法二继续执行,将frozen还原到100。
    至此,就造成数据库的脏写。同时,也造成了一个假象:我的方法执行后,数据库数据没有更新。

    解决办法

    给数据库字段加上版本号,更新时指定数据的版本号去更新,即使用乐观锁。

    广大朋友有其他的解决办法的,还希望能指出,谢谢!

    相关文章

      网友评论

          本文标题:Mybatis Update没执行

          本文链接:https://www.haomeiwen.com/subject/pjehfqtx.html