Несколько одновременных заданий Spring Batch, вызывающих взаимные блокировки - PullRequest
1 голос
/ 19 февраля 2020

Я использую Spring Batch 4.0.0, Spring Boot 2.2.0, java JDK 12.0.2, DB sql Server 2016.

Несколько заданий Spring Batch, выполняющихся одновременно, вызывая взаимоблокировки в Таблицы метаданных Spring Batch.

Я попробовал другое предложенное решение:

  1. Я установил идентичность для таблиц метаданных
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);
Я переопределил JobRepository и JobExplorer для настройки уровня изоляции
    @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();
    }

Но когда я запускаю несколько заданий, я часто / всегда получаю одну и ту же ошибку:

Не удалось увеличить идентичность; вложенное исключение - com.microsoft.sqlserver.jdb c .SQLServerException: транзакция заблокирована для ресурсов блокировки другого процесса и выбрана в качестве жертвы тупика. Перезапустите транзакцию.

1 Ответ

0 голосов
/ 02 марта 2020

Я нашел решение и опубликовал sh для тех, у кого такая же проблема; Я никогда не находил полное и всеобъемлющее решение, поэтому я хочу объяснить, как его решить и почему это произошло, давайте начнем. Эта тупик вызван обновлением и удалением из таблиц BATCH_STEP_EXECUTION_SEQ, BATCH_JOB_EXECUTION_SEQ и BATCH_JOB_SEQ, но почему это происходит? Может быть, потому что это не управляется должным образом, но реальная проблема заключается в том, что sql сервер начинает использовать последовательность с sql server 2012, поэтому Spring Batch пришлось использовать эти таблицы для управления последовательностью, у меня нет решения для этих если вы используете более старую версию сервера sql, чем 2012, ЭТО РУКОВОДСТВО ТОЛЬКО ДЛЯ ВЕРСИЙ ОТ 2012 .

1. Создайте последовательность в своей БД.

ОБРАТИТЕ ВНИМАНИЕ, ЧТОБЫ НАЧАТЬ ПОСЛЕДОВАТЕЛЬНОСТЬ ОТ ИДЕНТИФИКАТОРА, НЕ ИСПОЛЬЗУЕМОГО В ПРОЦЕССЕ, ЕСЛИ ВЫ НАЧИНАЕТЕ С 1, ВЫ ДОЛЖНЫ ОЧИСТИТЬ ВЕСЕННЫЕ ТАБЛИЦЫ И ВОЗМОЖНЫЕ ТАБЛИЦЫ, ГДЕ ИДЕНТИФИКАТОР РАБОТЫ USED.

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

2. Переопределить для метода JobRepository и JobExplorer (лично мне пришлось добавить его, потому что в противном случае у меня возникла проблема с префиксом таблиц пружинных пакетов).

Установите уровень изоляции на REPEATABLE_READ, потому что в противном случае у вас будет новая ошибка параллелизма на БД (Лично без этой настройки у меня были проблемы с BATCH_JOB_EXECUTION или BATCH_JOB_INSTANCE, я не помню только сейчас).

@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();
  }

}

3. Установите CustomDataFieldIncrementerFactory, потому что теперь он начинает управлять последовательностью из него.

 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;
  }
}

ЭТО ВСЕ, СЕЙЧАС ЭТО РАБОТАЕТ ХОРОШО !!!

Надеюсь это кому-нибудь пригодится.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...