即使有LockModeType.PESSIMISTIC_WRITE也陷入僵局



当我在 1 秒内触发 10 个请求时,org.springframework.dao.CannotAcquireLockException发生。

即使我用@Transactional(isolation = Isolation.SERIALIZABLE)标记了我的主要方法(在里面调用存储库方法(,并且我在存储库中的findBy方法具有@Lock(LockModeType.PESSIMISTIC_WRITE)注释。

在一个环境中一切正常,但在另一个环境中发生错误。知道为什么会发生错误吗?两种环境中的代码相同。

堆栈跟踪 1:

{"timestamp":">

2017-08-21T12:18:16.16+0000","status":500,"error":"Internal Server Error","exception":"org.springframework.orm.jpa.JpaSystemException","message": "com.mysql.jdbc.exceptions.jdbc4.MySQLTransactionRollbackException: 尝试获取锁定时发现死锁;尝试重新启动交易;嵌套异常是 javax.persistence.PersistenceException: com.mysql.jdbc.exceptions.jdbc4.MySQLTransactionRollbackException: 尝试获取锁定时发现死锁;尝试重新启动 事务","路径":"/汽车/丰田"}

堆栈跟踪 2:

{"timestamp":">

2017-08-21T12:11:57.57+0000","status":500,"error":"Internal Server Error","exception":"org.springframework.dao.CannotAcquireLockException","message":"无法执行语句;SQL [n/a]; 嵌套异常是 org.hibernate.exception.LockAcquisitionException: 无法执行语句","path":"/cars/toyota"}

当您尝试锁定一行但该行已被另一个事务锁定时,将引发错误。所以超时发生了。

添加@Transactional(isolation = Isolation.SERIALIZABLE)会使情况变得更糟,因为可序列化级别意味着一个事务锁定整个表(现代预言机可以以某种方式控制这一点,但对于MySQl来说,它实际上是等待锁定同一表的事务队列(。因此,第 10 个事务等待所有前 9 个事务并失败。

实际上我不明白为什么您需要锁定findBy方法。从逻辑上讲,该方法不应修改表,因此根本不需要锁定。

我建议更改逻辑以更快地进行一次调用,或者如果您有并发修改,甚至引入乐观锁(基于版本(。Hibernate通过添加@Version来允许这样做。

最新更新