現象
以下のコードのように、ほとんど間を空けずにjobをlaunchする。
ExecutorService s = Executors.newFixedThreadPool(2);
long time1 = new Date().getTime();
long time2 = time1 + 111111000;
s.execute(() -> doBatch(time1));
s.execute(() -> doBatch(time2));
void doBatch(long t) {
Map<String, JobParameter> p = new HashMap<String, JobParameter>();
p.put("a", new JobParameter(new Date(t)));
JobParameters jobParameters = new JobParameters(p);
l.run(job, jobParameters)
これを実行すると、以下のようなエラーになる。
Exception in thread "pool-1-thread-1" org.springframework.dao.CannotSerializeTransactionException: PreparedStatementCallback; SQL [INSERT into BATCH_JOB_INSTANCE(JOB_INSTANCE_ID, JOB_NAME, JOB_KEY, VERSION) values (?, ?, ?, ?)]; ORA-08177: このトランザクションのアクセスをシリアル化できません
; nested exception is java.sql.SQLException: ORA-08177: このトランザクションのアクセスをシリアル化できません
at org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator.doTranslate(SQLErrorCodeSQLExceptionTranslator.java:270)
at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:72)
at org.springframework.jdbc.core.JdbcTemplate.translateException(JdbcTemplate.java:1444)
at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:632)
これの原因は Spring Batch ORA-08177: can't serialize access for this transaction when running single job, SERIALIZED isolation level とかに書いてある。
解決策
というわけでIsolationLevel
をREAD_UNCOMMITTED
に変えてしまえばよい。
@Configuration
@EnableBatchProcessing
public class BatchConfiguration1 extends DefaultBatchConfigurer {
@Autowired
DataSource configDataSource;
@Autowired
PlatformTransactionManager configTxManager;
@Override
protected JobRepository createJobRepository() throws Exception {
JobRepositoryFactoryBean factoryBean = new JobRepositoryFactoryBean();
factoryBean.setDataSource(configDataSource);
factoryBean.setTransactionManager(configTxManager);
factoryBean.setIsolationLevelForCreate("ISOLATION_READ_COMMITTED");
factoryBean.setTablePrefix("BATCH_");
try {
factoryBean.afterPropertiesSet();
return factoryBean.getObject();
} catch (Exception e) {
throw new BatchConfigurationException(e);
}
}