当前位置: 首页 > 知识库问答 >
问题:

多个Spring批处理作业并发执行导致死锁

冉昊
2023-03-14

我使用的是spring Batch4.0.0、spring Boot2.2.0、java JDK12.0.2、db sql server 2016。

    null
ALTER TABLE [OWN].[BATCH_JOB_EXECUTION_SEQ]
ADD CONSTRAINT [PK_BATCH_JOB_EXECUTION_SEQ] PRIMARY KEY CLUSTERED ([ID] ASC);

ALTER TABLE [OWN].[BATCH_JOB_SEQ]
ADD CONSTRAINT [PK_BATCH_JOB_SEQ] PRIMARY KEY CLUSTERED ([ID] ASC);

ALTER TABLE [OWN].[BATCH_STEP_EXECUTION_SEQ]
ADD CONSTRAINT [PK_BATCH_STEP_EXECUTION_SEQ] PRIMARY KEY CLUSTERED ([ID] ASC);
    @Override
    protected JobRepository createJobRepository() throws Exception {
        JobRepositoryFactoryBean factory = new JobRepositoryFactoryBean();
        factory.setDatabaseType(DATABASE_TYPE);
        factory.setIsolationLevelForCreate(ISOLATION_REPEATABLE_READ);
        factory.setDataSource(dataSource);
        factory.setTransactionManager(getTransactionManager());
        factory.setTablePrefix(TABLE_PREFIX);
        factory.afterPropertiesSet();
        return factory.getObject();
    }

    @Override
    protected JobExplorer createJobExplorer() throws Exception {
        JobExplorerFactoryBean jobExplorerFactoryBean = new JobExplorerFactoryBean();
        jobExplorerFactoryBean.setDataSource(dataSource);
        jobExplorerFactoryBean.afterPropertiesSet();
        jobExplorerFactoryBean.setTablePrefix(TABLE_PREFIX);
        return jobExplorerFactoryBean.getObject();
    }

共有1个答案

苗冯浩
2023-03-14

我已经找到了解决方案,并为任何有同样问题的人发布;我从来没有找到一个完整和全面的解决方案,所以我想解释如何解决它,为什么它会发生,让我们开始。此死锁是由BATCH_STEP_EXECUTION_SEQ、BATCH_JOB_EXECUTION_SEQ和BATCH_JOB_SEQ表中的update和delete引起的,但为什么会发生这种情况呢?也许是因为事情没有得到正确的管理,但真正的问题是sql server从sql server 2012开始使用序列,所以spring batch不得不使用这些表来管理序列,对于那些使用比2012更旧版本的sql server的人来说,我没有解决方案,本指南仅适用于2012年的版本。

1.在数据库中创建序列。

注意从一个尚未处理的ID开始序列,否则,如果从1开始,则必须清理SPRING表和可能使用作业ID的表。

DROP TABLE [OWN].[BATCH_JOB_SEQ]
GO


DROP TABLE [OWN].[BATCH_JOB_EXECUTION_SEQ]
GO


DROP TABLE [OWN].[BATCH_STEP_EXECUTION_SEQ]
GO


CREATE SEQUENCE [OWN].[BATCH_JOB_SEQ] 
 AS [bigint]
 START WITH 1000
 INCREMENT BY 1
 MINVALUE -9223372036854775808
 MAXVALUE 9223372036854775807
 CACHE 
GO


CREATE SEQUENCE [OWN].[BATCH_JOB_EXECUTION_SEQ] 
 AS [bigint]
 START WITH 1000
 INCREMENT BY 1
 MINVALUE -9223372036854775808
 MAXVALUE 9223372036854775807
 CACHE 
GO

CREATE SEQUENCE [OWN].[BATCH_STEP_EXECUTION_SEQ] 
 AS [bigint]
 START WITH 1000
 INCREMENT BY 1
 MINVALUE -9223372036854775808
 MAXVALUE 9223372036854775807
 CACHE 
GO
@Component
public class SQLServerConfig extends DefaultBatchConfigurer{

  @Autowired
  private DataSource dataSource;

  @Value("${spring.batch.tablePrefix}")
  private String tablePrefix;

  @Override
  protected JobRepository createJobRepository() throws Exception {
      JobRepositoryFactoryBean factory = new JobRepositoryFactoryBean();
      factory.setDatabaseType(DatabaseType.SQLSERVER.name());
      factory.setDataSource(dataSource);
      factory.setTransactionManager(getTransactionManager());
      factory.setTablePrefix(tablePrefix);
      factory.setIncrementerFactory(new CustomDataFieldMaxValueIncrementerFactory(dataSource));
      factory.setIsolationLevelForCreate("ISOLATION_REPEATABLE_READ");
      factory.afterPropertiesSet();
      return factory.getObject();
  }

  @Override
  protected JobExplorer createJobExplorer() throws Exception {
      JobExplorerFactoryBean jobExplorerFactoryBean = new JobExplorerFactoryBean();
      jobExplorerFactoryBean.setDataSource(dataSource);
      jobExplorerFactoryBean.afterPropertiesSet();
      jobExplorerFactoryBean.setTablePrefix(tablePrefix);
      return jobExplorerFactoryBean.getObject();
  }

}
 public class CustomDataFieldMaxValueIncrementerFactory extends DefaultDataFieldMaxValueIncrementerFactory {


  private DataSource dataSource;


  public CustomDataFieldMaxValueIncrementerFactory(DataSource dataSource) {
      super(dataSource);
      this.dataSource = dataSource;
  }


  @Override
  public DataFieldMaxValueIncrementer getIncrementer(String incrementerType, String incrementerName) {
      DatabaseType databaseType = DatabaseType.valueOf(incrementerType.toUpperCase());
      DataFieldMaxValueIncrementer dataFieldMaxValueIncrementer = null;
      if (databaseType == DatabaseType.SQLSERVER) {
          dataFieldMaxValueIncrementer =  new CustomSqlServerMaxValueIncrementer(dataSource, incrementerName);
      } else {
          dataFieldMaxValueIncrementer = super.getIncrementer(incrementerType, incrementerName);
      }
      return dataFieldMaxValueIncrementer;
  }
}

仅此而已,现在运行良好!!!

我希望它对某人有用。

 类似资料:
  • 我在BatchScheduler中有多个计划作业,它在特定时间运行。简单的内置JobLauncher,这是同步的。在自然界中最初使用。现在,我想并行运行这些作业,这样没有作业可以等待其他作业完成。 我在不同的作业上尝试过@Async注释,但都不起作用。 然后,我尝试设置joblauncher.settaskexecutor(新的SimpleAsyncTaskExecutor())。但这并不奏效。

  • 我的spring批处理应用程序运行在连接到MySQL数据库(单实例)的PCF平台上,只有一个实例启动时运行良好

  • 我们正试图建立关于如何在大型IT服务中使用Spring Batch的标准,并具有不同的商业利益。 我们可能会有几个属于不同业务领域的批次。我们已经知道其中一些必须从所有批次通用的表中获取一些参数(即Java和COBOL;例如日期参数)。 我们将实现的Spring批处理作业的数量很难评估。没有重写现有COBOL批次的目标,只要有可能,就鼓励连续流程处理。 一些关于概念证明的问题不时出现,但目前几乎没

  • 我有一个作业流,我希望以以下方式运行它: 作业流将从Job1开始。在Job1成功完成后,Job1将同时启动Job2和Job4。 Job2和Job4将并行运行。 在Job2成功完成后,Job2将启动Job3。 在Job4成功完成后,Job4将启动Job5。 下面是job1.xml和job1的作业启动器类的代码片段: job1.xml uijobLauncher.java “job2,Job3”对和“

  • Spring批处理作业与flatfileitemreader(从csv读取)、processor(更新adwords api提要详细信息,对于csv文件中的每个记录(大约有40条记录),这一步大约需要40秒)和正在更新DB中记录的定制writer一起使用。 web.xml

  • 到目前为止,我正在运行spring批处理,只有一个作业。现在我想运行多个不同的作业,这意味着不同的功能。在我的配置文件中,我配置了两个具有不同id和不同名称的作业。现在我得负责这些工作。你能告诉我怎么跑吗。在这里,我的疑问是在我的java类中,我已经为运行批处理编写了这段代码。 对于其他作业,如何调用jobLauncher的run方法。 我的配置文件是