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