乐趣区

关于java:Transactional-导致报错-Lock-wait-timeout-exceeded

@Transactional 导致报错 Lock wait timeout exceeded; try restarting transaction

前言

最近线上我的项目报

Lock wait timeout exceeded; try restarting transaction

排查

  1. 百度 Lock wait timeout exceeded; try restarting transaction

    大略意思,就是 mysql 当中有死锁。须要排查

  2. 查看以后过程 show full processlist;
  3. 查看 mysql 锁表 select * from information_schema.innodb_trx;

    此处后果须要在意的是 trx_state,trx_mysql_thread_id 两个字段。

  4. 以上后果,没有 trx_state = LOCK_WAIT 的后果,就证实 mysql 内没有死锁。
  5. 迷茫了,不晓得该咋解决了。
  6. 监控 mysql 吧,不停的刷 show full processlist;
  7. 无心中发现一条 sql 查问语句,不停的再执行。去零碎内查看此 sql 语句。
  8. 发现零碎内一个 service 办法下面,应用了 @Transactional
  9. 那么问题来了,应用了 @Transactional 为什么会报 Lock wait timeout exceeded; try restarting transaction
  10. 猜测是否有一个工作,再执行此办法,其余的工作也来执行此办法。

测试猜测

  1. 写了两个办法,外面同时有 select,update

    @Override
        @Transactional
        public Person getPerson()
        {System.out.println("getPerson1 拜访程序启动:===========》" + System.currentTimeMillis());
    
            Person person = getById(1);
            System.out.println(person.getName());
    
            person.setName("测试"+System.currentTimeMillis());
    
            updateById(person);
    
            try {Thread.sleep(100000);
            } catch (InterruptedException e) {e.printStackTrace();
            }
    
            System.out.println("getPerson1 拜访程序完结:===========》" + System.currentTimeMillis());
            return person;
        }
    
    @Override
        @Transactional
        public Person getPerson2()
        {System.out.println("getPerson2 拜访程序启动:===========》" + System.currentTimeMillis());
    
            Person person = getById(2);
            System.out.println(person.getName());
    
            person.setName("测试"+System.currentTimeMillis());
    
            updateById(person);
    
            try {Thread.sleep(100000);
            } catch (InterruptedException e) {e.printStackTrace();
            }
    
            System.out.println("拜访程序完结:===========》" + System.currentTimeMillis());
            return person;
        }
  2. 写两个单元测试,别离同时申请

        @Test
        void demo2() {personService.getPerson();
        }
    
        @Test
        void demo3() {personService.getPerson2();
        }
  3. 后果
  • getById() 都是 1 的时候,复现了

  • getById() 不同的时候,没有复现

![1642411180281]

![1642411186155]

论断

  1. @Transactional 是行级锁
  2. mysql 期待事务锁 innodb_lock_wait_timeout 默认 50s
  3. 应用事务的状况下,尽量简化 service 代码。
退出移动版