Currently Spring Boot overrides Spring Batch default behaviour and specifies the connection-default isolation level for creating job metadata in the database (Spring Batch default is SERIALIZABLE with an option to override it).

This can cause issues where concurrent job executions can occur on the same database (our case).

So far the recommended way to workaround this was to override BasicBatchConfigurer (Spring Boot 1.x) or JpaBatchConfigurer (Spring Boot 2.x) and modify this method:

    @Override
    protected String determineIsolationLevel() {
        logger.warn("JPA does not support custom isolation levels, so locks may not be taken when launching Jobs");
        return "ISOLATION_DEFAULT";
    }

I propose to have a configuration property instead which can be used to disable this behaviour and allow Spring Batch to use custom isolation levels. For example, spring.batch.jpa.allow-custom-isolation-levels with false as default value which means keep the current behaviour.

Rationale: This behaviour was introduced in 2014 by this commit. Since then Spring Boot adopted HikariCP as default connection pool, which enables safe usage of custom isolation levels on top of JPA, because connections returned to HikariCP are properly cleaned up. Also, most JPA vendors allow this nowadays (see various JpaDialect implementations), however, not in all cases.

Since the connection pool can be changed to a less well-behaving one, also, not all JPA vendors support this, the default setting for the new property would be false. This would also ensure backwards compatibility.

Happy to contribute a PR for this enhancement request.

Comment From: snicoll

Thanks for the suggestion, paging @benas.

Comment From: fmbenhassine

Thank you for this suggestion. What is the expected way to provide a custom isolation level when spring.batch.jpa.allow-custom-isolation-levels is set to true? If I understand correctly, the user would still need to extend JpaBatchConfigurer and override createJobRepository to provide the custom isolation level (unless one wants to keep the default value from Spring Batch). Is that correct?

My thinking is that if the goal is to avoid extending a class to override a property, why not make the isolation level configurable with a property like other Batch properties (table-prefix, schema, etc)? What do you think?

Comment From: tiborsulyan

Good point, thank you! Let's say we have a spring.batch.jdbc.isolation-level-for-create property. - If it's not set, we keep the current behavior, which is ISOLATION_SERIALIZABLE without JPA and ISOLATION_DEFAULT with JPA, with the (slightly modified) warning still logged by JpaBatchConfigurer. - If it's set, the isolation level specified is always used.

What do you think?

Comment From: wilkinsona

@benas Could Batch provide a more strongly typed method for configuring the isolation level using Framework's org.springframework.transaction.annotation.Isolation enum?

Comment From: fmbenhassine

@tiborsulyan Thank you for your feedback. This seems reasonable to me.

@wilkinsona Yes, I created https://github.com/spring-projects/spring-batch/issues/4032 for that.

Comment From: tiborsulyan

We had some discussion with my colleagues and have another proposal.

What about changing the default behaviour to allow Spring Batch to use custom isolation levels by default? Since Spring Boot by default autoconfigures Hikari CP, this would be safe and concurrent Spring Batch jobs would then work by default.

I was thinking about the following logic (in JpaBatchConfigurer)

if spring.batch.jdbc.isolation-level-for-create is set, use that.
else {
 if datasource is a Hikari DS, use Spring Batch default (ISOLATION_SERIALIZABLE)
 else use database-default (ISOLATION_DEFAULT) and log the warning message
}

What do you think?

Comment From: wilkinsona

Thanks for the suggestion, @tiborsulyan, but I don't think we would want to introduce that level of coupling between JpaBatchConfigurer and a particular connection pool implementation.

Comment From: snicoll

Closing in favor of #28859