首页 > 解决方案 > 春季批处理中的OptimisticLockingFailureException

问题描述

我正面临 org.springframework.dao.OptimisticLockingFailureException: Attempt to update step execution id=xxx with wrong version (0),其中当前版本在我的应用程序中为 0。它正在工作,最近它开始在任何 Spring 批处理作业启动时抛出此异常(我们使用 Spring 批处理从 excel 批量导入和从 DB 导出文件,总共有 6 个作业)

异常是在第一步引发的,它只是从昨天开始发生,因为它之前工作正常。相同的代码适用于不同的环境。

深入挖掘 Spring Batch 源代码,我发现它正在尝试使用 step_execution_id 和 where 子句中的 version 更新行,但没有更新行。然后它抛出这个异常来通知是否有任何并发​​修改。但它试图更新的版本是 0,当前版本也是 0。很多人都问过这个问题,但是更新版本和当前版本是有区别的,在我的情况下是一样的。

我正在使用 Spring Batch 3.0.8 和 Hibernate 5.4.1。

我也尝试过清除春季批处理表。尝试重新启动,重新部署等。

PS - 请原谅我的英语。

标签: javaspring-batch

解决方案


当 2 个作业同时针对不同的数据服务器运行时,会发生 OptimisticLockingFailureException。看起来以下 BATCH 表被创建为复制表。

  1. BATCH_JOB_EXECUTION
  2. BATCH_JOB_EXECUTION_CONTEXT
  3. BATCH_JOB_EXECUTION_PARAMS
  4. BATCH_JOB_EXECUTION_SEQ
  5. BATCH_JOB_INSTANCE
  6. BATCH_JOB_SEQ
  7. BATCH_STEP_EXECUTION
  8. BATCH_STEP_EXECUTION_CONTEXT
  9. BATCH_STEP_EXECUTION_SEQ

作业序列 ID 和执行 ID 分别通过递增 BATCH_JOB_EXECUTION_SEQ 和 BATCH_JOB_SEQ 表中的当前值来创建。当您同时针对不同的数据服务器运行作业时,这将导致问题,因为从技术上讲,两个作业可以具有相同的作业执行 ID。

在我们的应用程序中,我们遇到了同样的问题。JOB1 & JOB2同时启动。JOB1针对DATASERVER1启动,JOB2同时针对DATASERVER2启动。在我们的例子中,JOB1JOB2都使用相同的执行 ID 20000002345 ,这从DATASERVER1DATASERVER2中的不一致数据可以看出。这导致 JOB1 失败,因为步骤表中的版本在 DATASERVER2 中途发生了更改。我们得到了以下异常。

异常: org.springframework.dao.OptimisticLockingFailureException:尝试使用错误版本 (1) 更新步骤异常 id=20000002345,当前版本为 2

由于重复的步骤执行 ID,JOB2 也失败了。

异常: 原因:org.springframework.dao.DuplicateKeyException: PreparedStatementCallback; SQL [INSERT into BATCH_JOB_INSTANCE(JOB_INSTANCE_ID, JOB_NAME, JOB_KEY, VERSION) 值 (?, ?, ?, ?)]; 键 1 的重复条目“1”;嵌套异常是 com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Duplicate entry '1' for key 1

解决方案: 我们要求 DBA关闭 所有数据服务器(DATASERVER1、DATASERVER2、DATASERVER3 等)上的 BATCH 表(9 个表以上)的复制。这解决了问题。在我们关闭复制后,这个问题永远不会发生。


推荐阅读