使用spring数据和mysql运行2事务方法时出现死锁

时间:2016-04-26 07:18:36

标签: java mysql spring transactions spring-data

我尝试使用spring boot,spring data和mysql来理解事务。

我创建了服务UpdateService,用于更新数据库中的记录。方法change和change2以事务方式执行。

@Autowired
private UserRepo userRepo;

@Transactional(isolation = Isolation.SERIALIZABLE)
public void change() {
    User user = userRepo.findOne("Jan");

    write("before change", user);
    sleep(2000);
    user.setPassword("new password");
    write("after change", user);
}

@Transactional(isolation = Isolation.SERIALIZABLE)
public void change2() {
    User user = userRepo.findOne("Jan");

    write("before change2", user);
    user.setSecondName("new name");
    write("after change2", user);
}

当我调用change和change2方法时,我收到了日志:

before change User(name=Jan, secondName=Adam, password=Kowalski)
before change2 User(name=Jan, secondName=Adam, password=Kowalski)
after change2 User(name=Jan, secondName=new name, password=Kowalski)
after change User(name=Jan, secondName=Adam, password=new password)

之后我也得到了例外:

com.mysql.jdbc.exceptions.jdbc4.MySQLTransactionRollbackException: Deadlock found when trying to get lock; try restarting transaction

我的问题是为什么交易更改2在更改完成之前就开始了?死锁的原因是什么?

1 个答案:

答案 0 :(得分:2)

贝娄是我的观点:

  

为什么交易更改2在更改完成之前就开始了?

对于mysql,首先需要关心 MySQL的版本,并查看this official site url about transaction。特别是,隔离级别 SERIALIZABLE

的描述
  • 此级别类似于REPEATABLE READ,但InnoDB隐式将所有普通SELECT语句转换为SELECT ...如果禁用自动提交,则锁定共享模式。如果启用了自动提交(也就是说,更改读取操作赢了<阻止读取操作 change2 ),SELECT是它自己的事务。因此,已知它是只读的,并且如果作为一致(非锁定)读取执行则可以序列化,并且不需要阻止其他事务。 (要强制普通SELECT阻止其他事务已修改所选行,请禁用自动提交。
  

死锁的原因是什么?

当执行更改更改2 的读取操作时,表示两个交易在同一行上保留共享锁。当执行更改(事务t1)和更改2 (事务t2)的写入操作时,t1将在t2上等待释放共享锁并且t2也将等待t1释放共享锁,这将导致死锁。

我建议你看看MySQL的交易和锁定机制

http://dev.mysql.com/doc/refman/5.7/en/innodb-transaction-model.html http://dev.mysql.com/doc/refman/5.7/en/innodb-lock-modes.html

希望能帮到你。