开发者社区> 问答> 正文

jfinal并发的事务死锁问题 400 请求报错 

@jfinal   
有一个controller,请求方法test,test加了事务@Before(TxSerializable.class)
有TableA,字段count

public class TableA extends Model<TableA> {
    public static final TableA dao=new TableA();

        public  void test() {
                TableA tableA=findById(1);
                int count=tableA.getInt("count");
                if(count>0){
                     tableA.set("count",count-1).update();
                     System.out.println("count:"+count);
                }
        }
}

部署一个tomcat,测试500个并发,60秒,这个写法测试没有问题

如果部署3个tomcat,测试500个并发,60秒,测试也没有问题,tomcat3会正确的走下去,tomcat1与tomcat2会报Deadlock found when trying to get lock;异常
去数据库看了下LATEST DETECTED DEADLOCK 
我猜想应该是这种情况:
tomcat1,请求test,update tableA set count=9 where id=1;  开启事务A对tablea加锁
tomcat2,请求test,update tableA set count=8 where id=1;开启事务B发现tablea已被加锁,就等待
tomcat3,请求test,update tableA set count=8 where id=1;开启事务C发现tablea已被加锁,就等待
当事务A完成,事务B发现事务C对tablea加了锁,事务B发现事务C对tablea加了锁,所以出现了死锁,
mysql让事务B回滚,事务C执行commit
不知道我理解的有没有误,tomcat集群,如何去解决这种死锁

展开
收起
kun坤 2020-05-29 12:06:20 627 0
1 条回答
写回答
取消 提交回答
  •      mysql 事务有可能发生死锁,死锁也不一定只出现在集群之下,单个 tomcat 多线程也是类似的情况。这个问题本质上是 mysql 数据库死锁的范畴了,建议使用 Db.update("update ....) 并且事务级别使用 TxRepeatableRead 来解决问题。
       楼主的代码先是通过 findById 读取出了数据,然后再通过 tableB.set("count", count - 1).update() 写入库,这类将数据先从库里面读出来,在内存中操作以后,再往库里面写的方式本身就会对事务级别要求提升至少一个等级,是不合算的,或许也增加了死锁的机率。
       建议直接 Db.update("update tableA set count = count -1 where id=?", id) 这样做既能提升效率,又能降低事务级别要求,还能降低死锁机率。测试下反馈给我 ######+1######这和jfinal 油漆么关系######我可至始至终没说和jfinal有关系,我只是说讨论下

    2020-05-29 12:06:29
    赞同 展开评论 打赏
问答排行榜
最热
最新

相关电子书

更多
Java Spring Boot开发实战系列课程【第16讲】:Spring Boot 2.0 实战Apache Kafka百万级高并发消息中间件与原理解析 立即下载
Java Spring Boot开发实战系列课程【第7讲】:Spring Boot 2.0安全机制与MVC身份验证实战(Java面试题) 立即下载
低代码开发师(初级)实战教程 立即下载