Java:MySql事务死锁:MySQLTransactionRollbackException: Deadlock found when trying to get lock...

目录

    • 场景
    • 报错信息
    • 原因
    • 解决


场景

1、service业务执行时出现异常

2、业务方法使用@Transaction注解控制事务

3、该业务比较耗时

4、有多个线程会调用该service业务方法


报错信息

### Error updating database.  Cause: com.mysql.cj.jdbc.exceptions.MySQLTransactionRollbackException: Deadlock found when trying to get lock; try restarting transaction
### The error may exist in com/xxx/mapper/aicall/poc/AicallBusiResult4pocMapper.java (best guess)
### The error may involve com.xxx.mapper.aicall.poc.AicallBusiResult4pocMapper.insertList-Inline
### The error occurred while setting parameters
### SQL: INSERT INTO t_aicall_busi_result4poc  ( sessionId,taskPID,taskDetPID,cusPID,customerName,caller,called,qSeq,qValue,createDate,vDNID )  VALUES   ( ?,?,?,?,?,?,?,?,?,?,? ) , ( ?,?,?,?,?,?,?,?,?,?,? ) , ( ?,?,?,?,?,?,?,?,?,?,? ) , ( ?,?,?,?,?,?,?,?,?,?,? ) , ( ?,?,?,?,?,?,?,?,?,?,? ) , ( ?,?,?,?,?,?,?,?,?,?,? ) , ( ?,?,?,?,?,?,?,?,?,?,? ) , ( ?,?,?,?,?,?,?,?,?,?,? ) , ( ?,?,?,?,?,?,?,?,?,?,? ) , ( ?,?,?,?,?,?,?,?,?,?,? ) , ( ?,?,?,?,?,?,?,?,?,?,? ) , ( ?,?,?,?,?,?,?,?,?,?,? ) , ( ?,?,?,?,?,?,?,?,?,?,? ) , ( ?,?,?,?,?,?,?,?,?,?,? ) , ( ?,?,?,?,?,?,?,?,?,?,? ) , ( ?,?,?,?,?,?,?,?,?,?,? )
### Cause: com.mysql.cj.jdbc.exceptions.MySQLTransactionRollbackException: Deadlock found when trying to get lock; try restarting transaction
; Deadlock found when trying to get lock; try restarting transaction; nested exception is com.mysql.cj.jdbc.exceptions.MySQLTransactionRollbackException: Deadlock found when trying to get lock; try restarting transaction
org.springframework.dao.DeadlockLoserDataAccessException: 
### Error updating database.  Cause: com.mysql.cj.jdbc.exceptions.MySQLTransactionRollbackException: Deadlock found when trying to get lock; try restarting transaction
### The error may exist in com/xxx/mapper/aicall/poc/AicallBusiResult4pocMapper.java (best guess)
### The error may involve com.xxx.mapper.aicall.poc.AicallBusiResult4pocMapper.insertList-Inline
### The error occurred while setting parameters
### SQL: INSERT INTO t_aicall_busi_result4poc  ( sessionId,taskPID,taskDetPID,cusPID,customerName,caller,called,qSeq,qValue,createDate,vDNID )  VALUES   ( ?,?,?,?,?,?,?,?,?,?,? ) , ( ?,?,?,?,?,?,?,?,?,?,? ) , ( ?,?,?,?,?,?,?,?,?,?,? ) , ( ?,?,?,?,?,?,?,?,?,?,? ) , ( ?,?,?,?,?,?,?,?,?,?,? ) , ( ?,?,?,?,?,?,?,?,?,?,? ) , ( ?,?,?,?,?,?,?,?,?,?,? ) , ( ?,?,?,?,?,?,?,?,?,?,? ) , ( ?,?,?,?,?,?,?,?,?,?,? ) , ( ?,?,?,?,?,?,?,?,?,?,? ) , ( ?,?,?,?,?,?,?,?,?,?,? ) , ( ?,?,?,?,?,?,?,?,?,?,? ) , ( ?,?,?,?,?,?,?,?,?,?,? ) , ( ?,?,?,?,?,?,?,?,?,?,? ) , ( ?,?,?,?,?,?,?,?,?,?,? ) , ( ?,?,?,?,?,?,?,?,?,?,? )
### Cause: com.mysql.cj.jdbc.exceptions.MySQLTransactionRollbackException: Deadlock found when trying to get lock; try restarting transaction
; Deadlock found when trying to get lock; try restarting transaction; nested exception is com.mysql.cj.jdbc.exceptions.MySQLTransactionRollbackException: Deadlock found when trying to get lock; try restarting transaction
	at org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator.doTranslate(SQLErrorCodeSQLExceptionTranslator.java:268)
	at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:73)
	at org.mybatis.spring.MyBatisExceptionTranslator.translateExceptionIfPossible(MyBatisExceptionTranslator.java:91)
	at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:441)
	at com.sun.proxy.$Proxy115.insert(Unknown Source)
	at org.mybatis.spring.SqlSessionTemplate.insert(SqlSessionTemplate.java:272)
	at org.apache.ibatis.binding.MapperMethod.execute(MapperMethod.java:62)
	at org.apache.ibatis.binding.MapperProxy$PlainMethodInvoker.invoke(MapperProxy.java:145)
	at org.apache.ibatis.binding.MapperProxy.invoke(MapperProxy.java:86)
	at com.sun.proxy.$Proxy170.insertList(Unknown Source)
	at sun.reflect.GeneratedMethodAccessor806.invoke(Unknown Source)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.springsource.loaded.ri.ReflectiveInterceptor.jlrMethodInvoke(ReflectiveInterceptor.java:1427)
	at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:344)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:198)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
	at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:137)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
	at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:241)
	at com.sun.proxy.$Proxy171.insertList(Unknown Source)
	at com.xxx.service.aicall.api.impl.AiCallTaskServiceImpl.pocSetResult(AiCallTaskServiceImpl.java:784)
	at com.xxx.service.aicall.api.impl.AiCallTaskServiceImpl$$FastClassBySpringCGLIB$$7b5e29ab.invoke(<generated>)
	at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218)
	at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:792)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
	at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:762)
	at org.springframework.transaction.interceptor.TransactionInterceptor$1.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.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:762)
	at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:707)
	at com.xxx.service.aicall.api.impl.AiCallTaskServiceImpl$$EnhancerBySpringCGLIB$$32ffeb7a.pocSetResult(<generated>)
	at com.xxx.thread.PocSetResultTaskThr.run(PocSetResultTaskThr.java:32)
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)
	at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:97)
	at com.mysql.cj.jdbc.exceptions.SQLExceptionsMapping.translateException(SQLExceptionsMapping.java:122)
	at com.mysql.cj.jdbc.ClientPreparedStatement.executeInternal(ClientPreparedStatement.java:970)
	at com.mysql.cj.jdbc.ClientPreparedStatement.execute(ClientPreparedStatement.java:387)
	at com.alibaba.druid.pool.DruidPooledPreparedStatement.execute(DruidPooledPreparedStatement.java:497)
	at sun.reflect.GeneratedMethodAccessor103.invoke(Unknown Source)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.springsource.loaded.ri.ReflectiveInterceptor.jlrMethodInvoke(ReflectiveInterceptor.java:1427)
	at org.apache.ibatis.logging.jdbc.PreparedStatementLogger.invoke(PreparedStatementLogger.java:59)
	at com.sun.proxy.$Proxy390.execute(Unknown Source)
	at org.apache.ibatis.executor.statement.PreparedStatementHandler.update(PreparedStatementHandler.java:47)
	at org.apache.ibatis.executor.statement.RoutingStatementHandler.update(RoutingStatementHandler.java:74)
	at org.apache.ibatis.executor.SimpleExecutor.doUpdate(SimpleExecutor.java:50)
	at org.apache.ibatis.executor.BaseExecutor.update(BaseExecutor.java:117)
	at org.apache.ibatis.executor.CachingExecutor.update(CachingExecutor.java:76)
	at sun.reflect.GeneratedMethodAccessor420.invoke(Unknown Source)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.springsource.loaded.ri.ReflectiveInterceptor.jlrMethodInvoke(ReflectiveInterceptor.java:1427)
	at org.apache.ibatis.plugin.Plugin.invoke(Plugin.java:64)
	at com.sun.proxy.$Proxy388.update(Unknown Source)
	at org.apache.ibatis.session.defaults.DefaultSqlSession.update(DefaultSqlSession.java:194)
	at org.apache.ibatis.session.defaults.DefaultSqlSession.insert(DefaultSqlSession.java:181)
	at sun.reflect.GeneratedMethodAccessor437.invoke(Unknown Source)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.springsource.loaded.ri.ReflectiveInterceptor.jlrMethodInvoke(ReflectiveInterceptor.java:1427)
	at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:427)
	... 31 common frames omitted

原因

1、该业务方法执行完毕比较耗时

2、有多个线程会执行该业务

综合以上两点,如果多个线程同时执行,就会出现死锁的情况


解决

手动控制事务,把比较耗时的代码放在事务之外处理,以减少持有事务锁的时间


1、以下业务耗时较长,且有概率多个线程同时执行

@Override
@Transactional
public Integer method1(JSONObject json) {
	//1、因为业务需要,这里执行一些比耗时的代码,如for循环等
	
	//2、查询数据
	xxxMapper.select(param1, param2);
	
	//3、因为业务需要,这里再次执行一些比耗时的代码

	//4、删除数据
	xxxMapper.delete(param1, param2);

	//5、插入数据
	xxxMapper.insert(param);
}

2、对该业务进行优化

@Slf4j
@Service
public class xxxServiceImpl extends BaseServiceImpl<xxx> implements xxxService {

	//1、注入对应的事务管理器
	//若项目上只有一个数据源,则不需要使用@Qualifier
	@Qualifier(BaseDataSourceConfiguration.TRANSACTION_MANAGER_NAME)
	@Autowired
	private DataSourceTransactionManager dataSourceTransactionManager;


	@Override
	//注意:这里将@Transactional注释掉,用try/catch来控制事务的提交和回滚
	//@Transactional
	public Integer method1(JSONObject json) {
		try {
			//1、因为业务需要,这里执行一些比耗时的代码,如for循环等
	
			//2、查询数据
			xxxMapper.select(param1, param2);
	
			//3、因为业务需要,这里再次执行一些比耗时的代码

			//4、在真正操作数据库(增、删、改)之前手动开启事务
			// 获取事务定义
			DefaultTransactionDefinition df = new DefaultTransactionDefinition();
			// 设置事务隔离级别,开启新的数据
			df.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
			// 获取事务状态,相当于开启事务
			TransactionStatus transaction = dataSourceTransactionManager.getTransaction(df);

			//5、删除数据
			xxxMapper.delete(param1, param2);

			//6、插入数据
			xxxMapper.insert(param);

			//7、提交事务
			dataSourceTransactionManager.commit(transaction);
		} catch (Exception e) {
            //8、回滚事务
			dataSourceTransactionManager.rollback(transaction);
        }
	}
}

说明:这里是把事务的开启时机,尽量往后移,在真正操作数据库之前才开启事务,持有事务锁的时间减短了,那么多线程同时争抢锁的概率也就降低了

你可能感兴趣的:(Java异常处理,Mysql,java,mysql)