hibernate 查询方法报死锁异常

现象

Caused by: com.mysql.cj.jdbc.exceptions.MySQLTransactionRollbackException: Deadlock found when trying to get lock; try restarting transaction
	at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:123)

http 接口报错,查看 Java 错误日志中的异常堆栈,程序堆栈顶部是一个 service/repository 类的查询方法。

查看 MySQL 的死锁日志,发现两个事务的 update 语句造成的死锁。

疑问

从 Java 的异常来看,业务代码只是执行了查询方法,和 update 无关,而且查询的表名甚至和 MySQL 死锁日志中的更新表名都不一致。这个查询的 Java 方法为什么会触发死锁呢?

原因

进一步查看完整堆栈(前面只看了业务代码的堆栈,没有关于 hibernate 的堆栈)。发现中间确实有查询org.hibernate.query.Query.getResultList,然后往上有org.hibernate.persister.entity.AbstractEntityPersister.update,其中间有一个org.hibernate.event.internal.DefaultAutoFlushEventListener.onAutoFlush

汇总起来看就是:查询时,先判断是否存在需要flush的实体对象,如果有则先执行flushupdate)。

flush 的对象是当前堆栈显示代码之前执行查询的,但是这中间该对象在其它线程被修改过,导致当前线程判断出需要 flush,进而触发了 MySQL 死锁问题。

Caused by: org.hibernate.exception.LockAcquisitionException: could not execute statement
	at org.hibernate.dialect.MySQLDialect$3.convert(MySQLDialect.java:547)
	at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:42)
	at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:113)
	at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:99)
	at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:178)
	at org.hibernate.persister.entity.AbstractEntityPersister.update(AbstractEntityPersister.java:3377)
	at org.hibernate.persister.entity.AbstractEntityPersister.updateOrInsert(AbstractEntityPersister.java:3250)
	at org.hibernate.persister.entity.AbstractEntityPersister.update(AbstractEntityPersister.java:3651)
	at org.hibernate.action.internal.EntityUpdateAction.execute(EntityUpdateAction.java:146)
	at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:604)
	at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:478)
	at org.hibernate.event.internal.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:356)
	at org.hibernate.event.internal.DefaultAutoFlushEventListener.onAutoFlush(DefaultAutoFlushEventListener.java:53)
	at org.hibernate.internal.SessionImpl.autoFlushIfRequired(SessionImpl.java:1433)
	at org.hibernate.internal.SessionImpl.list(SessionImpl.java:1519)
	at org.hibernate.query.internal.AbstractProducedQuery.doList(AbstractProducedQuery.java:1598)
	at org.hibernate.query.internal.AbstractProducedQuery.list(AbstractProducedQuery.java:1566)
	at org.hibernate.query.Query.getResultList(Query.java:132)
	at org.springframework.data.jpa.repository.query.JpaQueryExecution$CollectionExecution.doExecute(JpaQueryExecution.java:126)
	at org.springframework.data.jpa.repository.query.JpaQueryExecution.execute(JpaQueryExecution.java:88)
	at org.springframework.data.jpa.repository.query.AbstractJpaQuery.doExecute(AbstractJpaQuery.java:154)
	at org.springframework.data.jpa.repository.query.AbstractJpaQuery.execute(AbstractJpaQuery.java:142)
	at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.doInvoke(RepositoryFactorySupport.java:619)
	at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:606)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
	at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:80)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
	at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:367)
	at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:118)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
	at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:139)
	... 185 common frames omitted

总结

终究还是要看异常堆栈,及其源码。

  • 8
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值