question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

EclipseLinkJpaDialect applies per-transaction isolation level to shared DatabasePlatform

See original GitHub issue

spring orm version: 5.1.4.RELEASE

In EclipseLinkJpaDialect class line 81

if (definition.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT) {
	// Pass custom isolation level on to EclipseLink's DatabaseLogin configuration
	// (since Spring 4.1.2)
	UnitOfWork uow = entityManager.unwrap(UnitOfWork.class);
	uow.getLogin().setTransactionIsolation(definition.getIsolationLevel());
}

for instance: If txA beginTransaction and there is Isolation.SERIALIZABLE around the repository class, the TransactionIsolation in uow.getLogin() will be changed to Isolation.SERIALIZABLE. Then txB beginTransaction with Isolation.DEFAULT, the condition is not met, TransactionIsolation in uow.getLogin() still be SERIALIZABLE.

I think the right code should like this:

if (definition.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT
   && definition.getIsolationLevel() != entityManager.unwrap(UnitOfWork.class).getLogin().setTransactionIsolation()) {
	// ... 
}

Issue Analytics

  • State:open
  • Created 3 years ago
  • Comments:13 (8 by maintainers)

github_iconTop GitHub Comments

1reaction
toalexivanovcommented, Jun 15, 2020

transactionIsolation field in org.eclipse.persistence.internal.databaseaccess.DatabasePlatform is not synchronized. This is the root cause.

DatabasePlatform stores various database settings that rarely change at runtime. Perhaps that is what implementors of EclipseLink meant for transactionIsolation as well, set it once and forget. This is how most database applications use it anyway. It is rare for an application to use transaction isolation level other than the default.

An instance of this class is called by JpaTransactionManager which is a Spring bean in our application. Application accesses this bean from multiple threads. Now you can imagine multiple service threads starting transactions with different isolation levels concurrently. Also statement in EclipseLinkAdapter.beginTransaction() checks requested transaction isolation level and simply returns without setting it if it is equal to a default value. Transaction isolation level is set to default automatically in Spring if it is not set explicitly. In majority of our usages, we don’t set this level explicitly for one simple reason - default isolation level READ_COMMITTED is sufficient for our purposes most of the time. However it means that transaction by explicitly setting non-default isolation level overrides this level for all subsequent transactions. Not only that, depending on timing, a transaction in one thread could silently override transaction isolation level in another thread.

To remedy this problem I supplied CustomOraclePlatform bean where I override setTransactionIsolation() and getTransactionIsolation(). These methods make use of a ThreadLocal field represeting isolation level. Now each thread gets its own isolation level. However transactions with different isolation levels in the same thread would still experience the problem. Also cached thread pools do not reset ThreadLocals. For that we need to prevent EclipseLinkJpaDialect from invoking short-circuit check for default level. This can be be done by translating TransactionDefinition.ISOLATION_DEFAULT to TransactionDefinition.ISOLATION_READ_COMMITTED (or whatever default level is appropriate for your database) in EclipseLinkJpaDialect.beginTransaction(). This is exactly what I did in CustomEclipseLinkJpaDialect.

0reactions
jhoellercommented, Jun 19, 2020

We could try to operate directly on the JDBC Connection but we’d have to clarify when exactly an EclipseLink Session obtains its JDBC Connection and when exactly it returns the Connection to the pool. Hibernate has well-defined connection policies for that purpose, whereas with EclipseLink we’d probably have to rely on implementation behavior (hoping that it won’t change).

Read more comments on GitHub >

github_iconTop Results From Across the Web

Spring managed transactions, EclipseLink JPA, custom ...
Configure the database transaction isolation as serializable. Configure objects as isolated (see Configuring Cache Isolation at the Project Level or Configuring ...
Read more >
EclipseLinkJpaDialect (Spring Framework 6.0.2 API)
This allows for reusing the same JDBC Connection throughout an entire EclipseLink transaction, for enforced isolation and consistent visibility with JDBC access ...
Read more >
A beginner's guide to transaction isolation levels in enterprise ...
All databases allow you to set the default transaction isolation level. Typically, the database is shared among multiple applications and ...
Read more >
Spring managed transactions, EclipseLink JPA, custom ...
EclipseLinkJpaDialect#beginTransaction does not support any transaction isolation level but the default. So then I tried getting to ...
Read more >
Need custom isolation level for OpenJPA (DB2Dialect) - IBM
Any guidelines to have DB2 spesific isolation support on OpenJPA ? ... Seems like the 'problem' is that isolationLevel does not apply on...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found