Spring batch 使用默认隔离级别并发创建作业实例会导致MySQL死锁吗?

Spring batch 使用默认隔离级别并发创建作业实例会导致MySQL死锁吗?,spring-batch,Spring Batch,最近,我们运行了一个测试,该测试同时创建了不同的Spring批处理作业实例(例如,并行10个线程,作业名称相似但不同,例如使用相同的前缀)。而且触发MySQL异常报告的死锁错误相当容易 org.springframework.dao.deadlocklesserDataAccessException:PreparedStatementCallback;SQL[插入批处理作业实例(作业实例ID、作业名称、作业密钥、版本)值(?,,?)];尝试获取锁时发现死锁;尝试重新启动事务;嵌套异常为com.m

最近,我们运行了一个测试,该测试同时创建了不同的Spring批处理作业实例(例如,并行10个线程,作业名称相似但不同,例如使用相同的前缀)。而且触发MySQL异常报告的死锁错误相当容易

org.springframework.dao.deadlocklesserDataAccessException:PreparedStatementCallback;SQL[插入批处理作业实例(作业实例ID、作业名称、作业密钥、版本)值(?,,?)];尝试获取锁时发现死锁;尝试重新启动事务;嵌套异常为com.mysql.jdbc.exceptions.jdbc4.MySQLTransactionRollbackException:尝试获取锁时发现死锁;尝试在org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator.doTranslate(SQLErrorCodeSQLExceptionTranslator.java:267)org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:72)上重新启动事务org.springframework.jdbc.core.JdbcTemplate.translateException(JdbcTemplate.java:1443)org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:633)org.springframework.jdbc.core.JdbcTemplate.update(JdbcTemplate.java:862)org.springframework.JdbcTemplate.JdbcTemplate.java:917位于org.springframework.batch.core.repository.dao.JdbcJobInstanceDao.CreateJobInstanceDao(JdbcJobInstanceDao.java:120)org.springframework.batch.core.repository.support.SimpleJobRepository.createJobExecution(SimpleJobRepository.java:140)的org.springframeworksun.reflect.NativeMethodAccessorImpl.invoke0(本机方法)sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)java.lang.reflect.Method.invoke(Method.java:498)位于org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:344)

我们搜索了关于死锁的现有报告,发现有些报告是特定于SQLServer的,如:()。在分析用于创建作业(可序列化)的隔离级别和操作顺序后,我们认为死锁可能触发如下:

1、 在创建作业实例之前,代码会首先查询batch_job_instance表,检查实例是否已经存在(大约3次),在SERIALIZABLE模式下,这将在MySQL中持有shared next key lock(),锁定与作业名称相关的范围内的记录

2、 线程2想要创建job2并在batch_job_实例中插入一行,而线程3想要做同样的事情,因为两个线程都持有相同的read next key lock,并且需要插入的行也在key作用域中,所以会发生死锁

参考链接here(),我们尝试将隔离级别更改为REPEATABLE_READ,这在没有任何死锁的情况下工作

因此,这里的关键问题是:

将隔离级别设置为REPEATABLE_READ是否是此处推荐的解决方案?此解决方案是否有任何副作用,因为它未设置为默认选项

非常感谢

我们尝试将隔离级别更改为可重复读取,这在没有任何死锁的情况下工作

因此,这里的关键问题是:将隔离级别设置为REPEATABLE_READ是这里推荐的解决方案吗?该解决方案是否有任何副作用,因为它没有设置为默认选项

是的,就是这样。如果SERIALIZABLE过于激进,则可以对作业存储库使用不那么激进的隔离级别。这就是为什么提供了
setIsolationLevelForCreate
。这实际上记录在其:


谢谢艾哈迈迪,我想知道如果RealabyLyRead工作得很好,没有死锁和任何其他副作用,我们应该考虑把它作为Spring批量的默认选项吗?这里的可串行化VS Realabl Lead?我认为SERIALIZABLE是最好的默认设置,因为默认情况下,我们应该尝试防止任何并发性问题,然后如果攻击性较低的级别也能正常工作,则可以放松此约束。
ISOLATION_REPEATABLE_READ would work as well