Skip to content

Commit aaebf57

Browse files
committed
Set and reset shared isolation value within synchronized transaction begin
Since EclipseLink applies a custom transaction isolation value to its shared DatabasePlatform instance, we need to immediately restore the original value after the current value got picked up for JDBC Connection access inside of EclipseLink. In order to not interfere with concurrent transactions, we need to use synchronization around the transaction begin sequence in such a case. Closes gh-29997
1 parent 24fa879 commit aaebf57

File tree

2 files changed

+34
-17
lines changed

2 files changed

+34
-17
lines changed

spring-orm/src/main/java/org/springframework/orm/jpa/vendor/EclipseLinkJpaDialect.java

Lines changed: 32 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2018 the original author or authors.
2+
* Copyright 2002-2023 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -21,6 +21,7 @@
2121

2222
import jakarta.persistence.EntityManager;
2323
import jakarta.persistence.PersistenceException;
24+
import org.eclipse.persistence.sessions.DatabaseLogin;
2425
import org.eclipse.persistence.sessions.UnitOfWork;
2526

2627
import org.springframework.jdbc.datasource.ConnectionHandle;
@@ -31,8 +32,7 @@
3132

3233
/**
3334
* {@link org.springframework.orm.jpa.JpaDialect} implementation for Eclipse
34-
* Persistence Services (EclipseLink). Developed and tested against EclipseLink 2.7;
35-
* backwards-compatible with EclipseLink 2.5 and 2.6 at runtime.
35+
* Persistence Services (EclipseLink). Compatible with EclipseLink 3.0/4.0.
3636
*
3737
* <p>By default, this class acquires an early EclipseLink transaction with an early
3838
* JDBC Connection for non-read-only transactions. This allows for mixing JDBC and
@@ -77,22 +77,40 @@ public void setLazyDatabaseTransaction(boolean lazyDatabaseTransaction) {
7777
public Object beginTransaction(EntityManager entityManager, TransactionDefinition definition)
7878
throws PersistenceException, SQLException, TransactionException {
7979

80-
if (definition.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT) {
80+
int currentIsolationLevel = definition.getIsolationLevel();
81+
if (currentIsolationLevel != TransactionDefinition.ISOLATION_DEFAULT) {
8182
// Pass custom isolation level on to EclipseLink's DatabaseLogin configuration
82-
// (since Spring 4.1.2)
83+
// (since Spring 4.1.2 / revised in 5.3.28)
8384
UnitOfWork uow = entityManager.unwrap(UnitOfWork.class);
84-
uow.getLogin().setTransactionIsolation(definition.getIsolationLevel());
85+
DatabaseLogin databaseLogin = uow.getLogin();
86+
// Synchronize on shared DatabaseLogin instance (-> concurrent transactions)
87+
synchronized (databaseLogin) {
88+
int originalIsolationLevel = databaseLogin.getTransactionIsolation();
89+
// Apply current isolation level value, if necessary.
90+
if (currentIsolationLevel != originalIsolationLevel) {
91+
databaseLogin.setTransactionIsolation(currentIsolationLevel);
92+
}
93+
// Transaction begin including enforced JDBC Connection access
94+
// (picking up current isolation level from DatabaseLogin)
95+
entityManager.getTransaction().begin();
96+
uow.beginEarlyTransaction();
97+
entityManager.unwrap(Connection.class);
98+
// Restore original isolation level value, if necessary.
99+
if (currentIsolationLevel != originalIsolationLevel) {
100+
databaseLogin.setTransactionIsolation(originalIsolationLevel);
101+
}
102+
}
85103
}
86-
87-
entityManager.getTransaction().begin();
88-
89-
if (!definition.isReadOnly() && !this.lazyDatabaseTransaction) {
90-
// Begin an early transaction to force EclipseLink to get a JDBC Connection
91-
// so that Spring can manage transactions with JDBC as well as EclipseLink.
92-
entityManager.unwrap(UnitOfWork.class).beginEarlyTransaction();
104+
else {
105+
entityManager.getTransaction().begin();
106+
if (!definition.isReadOnly() && !this.lazyDatabaseTransaction) {
107+
// Begin an early transaction to force EclipseLink to get a JDBC Connection
108+
// so that Spring can manage transactions with JDBC as well as EclipseLink.
109+
entityManager.unwrap(UnitOfWork.class).beginEarlyTransaction();
110+
}
93111
}
94112

95-
return null;
113+
return entityManager;
96114
}
97115

98116
@Override

spring-orm/src/main/java/org/springframework/orm/jpa/vendor/EclipseLinkJpaVendorAdapter.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2022 the original author or authors.
2+
* Copyright 2002-2023 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -30,8 +30,7 @@
3030

3131
/**
3232
* {@link org.springframework.orm.jpa.JpaVendorAdapter} implementation for Eclipse
33-
* Persistence Services (EclipseLink). Developed and tested against EclipseLink 2.7;
34-
* backwards-compatible with EclipseLink 2.5 and 2.6 at runtime.
33+
* Persistence Services (EclipseLink). Compatible with EclipseLink 3.0/4.0.
3534
*
3635
* <p>Exposes EclipseLink's persistence provider and EntityManager extension interface,
3736
* and adapts {@link AbstractJpaVendorAdapter}'s common configuration settings.

0 commit comments

Comments
 (0)