spring 数据库 mysql 上小型 table 的简单 spring 数据 jpa 事务无限期挂起

Simple spring data jpa transaction to small table on mysql database is hanging indefinitely

我有一个 spring 数据 jpa 查询,它使用悲观锁从 mysql table 中读取一行。在我的环境中,这个 table 只包含一行,所以应该很快。

spring 数据 jpa 函数名为 FindTopByIsCurrent(boolean iscurrent),它应该只检索 table.

的唯一元素

当命令 运行s 时,它会无限期地挂起。检查 SHOW ENGINE INNODB STATUS

的输出
---TRANSACTION 170279307,

ACTIVE 3859 sec
2 lock struct(s), heap size 1136, 1 row lock(s)
MySQL thread id 11665, OS thread handle 140237095196416, query id 770252923 10.51.5.32 root
TABLE LOCK table `mydb`.`mytable` trx id 170279307 lock mode IS
RECORD LOCKS space id 722 page no 3 n bits 72 index PRIMARY of table `mydb`.`mytable` trx id 170279307 lock mode S
Record lock, heap no 2 PHYSICAL RECORD: n_fields 5; compact format; info bits 0
 0: len 4; hex 34303030; asc 4000;;
 1: len 4; hex 80000000; asc     ;;
 2: len 6; hex 0000000bf801; asc       ;;
 3: len 7; hex b2000001260110; asc     &  ;;
 4: len 1; hex 01; asc  ;;

此 table 仅供此一个应用程序使用,show engine 的列表中没有其他事务。性能模式线程 table 没有 ID 为 11665 的线程。此外,当我登录数据库并 运行

select * from mytable

我立即收到我需要的任何信息,所以 table 没有以阻止读取的方式被锁定。

这里是table(is_current是真位)

*************************** 
1. row 
***************************

version: 4000
local_index: 0

 is_current: 

1 row in set (0.00 sec)

此外,这是一个随机问题。在大约 3/4 的情况下,不会出现此错误。在 1/4 中,这出现在服务尝试的每个事务中。进一步调试显示挂起发生在查询中间,阻塞发生在我们有机会提交之前

显然这是一个死锁,但它与SQL无关。

我是 运行 另一个线程中的另一个事务。该事务涉及从不同数据库(同一服务器)中的不同 table 读取数据。此外,我 运行 的两个事务都发生在它们 spring bean 的 PostConstruct 方法中。我有点对 SQL 相关原因有所了解,而忽略了不相关的读取可能导致问题的可能性

这些事务显然需要锁定特定的 SingletonSupplier 和 ConcurrentHashmap,它们各自锁定了两者之一并相互死锁。

at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.getSingletonFactoryBeanForTypeCheck(AbstractAutowireCapableBeanFactory.java:1006)
- waiting to lock <0x00000000c189bf40> (a java.util.concurrent.ConcurrentHashMap)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.getTypeForFactoryBean(AbstractAutowireCapableBeanFactory.java:907)
at org.springframework.beans.factory.support.AbstractBeanFactory.isTypeMatch(AbstractBeanFactory.java:637)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doGetBeanNamesForType(DefaultListableBeanFactory.java:583)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanNamesForType(DefaultListableBeanFactory.java:550)
at org.springframework.beans.factory.BeanFactoryUtils.beanNamesForTypeIncludingAncestors(BeanFactoryUtils.java:265)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.findAutowireCandidates(DefaultListableBeanFactory.java:1555)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1352)
at org.springframework.beans.factory.support.DefaultListableBeanFactory$DependencyObjectProvider.getObject(DefaultListableBeanFactory.java:1988)
at org.springframework.boot.actuate.autoconfigure.metrics.data.RepositoryMetricsAutoConfiguration$$Lambda1/1598942787.get(Unknown Source)
at org.springframework.util.function.SingletonSupplier.get(SingletonSupplier.java:97)
- locked <0x00000000c2ca1c40> (a org.springframework.util.function.SingletonSupplier)
at org.springframework.boot.actuate.metrics.data.MetricsRepositoryMethodInvocationListener.lambda$afterInvocation[=10=](MetricsRepositoryMethodInvocationListener.java:87)
at org.springframework.boot.actuate.metrics.data.MetricsRepositoryMethodInvocationListener$$Lambda21/652710755.accept(Unknown Source)
at org.springframework.boot.actuate.metrics.AutoTimer.apply(AutoTimer.java:109)
at org.springframework.boot.actuate.metrics.data.MetricsRepositoryMethodInvocationListener.afterInvocation(MetricsRepositoryMethodInvocationListener.java:86)
at org.springframework.data.repository.core.support.RepositoryInvocationMulticaster$DefaultRepositoryInvocationMulticaster.notifyListeners(RepositoryInvocationMulticaster.java:76)
at org.springframework.data.repository.core.support.RepositoryMethodInvoker.doInvoke(RepositoryMethodInvoker.java:148)
at org.springframework.data.repository.core.support.RepositoryMethodInvoker.invoke(RepositoryMethodInvoker.java:121)
at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.doInvoke(QueryExecutorMethodInterceptor.java:159)
at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.invoke(QueryExecutorMethodInterceptor.java:138)
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.TransactionInterceptor.proceedWithInvocation(TransactionInterceptor.java:123)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:388)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:119)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:137)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:145)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:215)