Browse Source

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
pull/30619/head
Juergen Hoeller 2 years ago
parent
commit
aaebf5749c
  1. 46
      spring-orm/src/main/java/org/springframework/orm/jpa/vendor/EclipseLinkJpaDialect.java
  2. 5
      spring-orm/src/main/java/org/springframework/orm/jpa/vendor/EclipseLinkJpaVendorAdapter.java

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

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 the original author or authors.
* Copyright 2002-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -21,6 +21,7 @@ import java.sql.SQLException; @@ -21,6 +21,7 @@ import java.sql.SQLException;
import jakarta.persistence.EntityManager;
import jakarta.persistence.PersistenceException;
import org.eclipse.persistence.sessions.DatabaseLogin;
import org.eclipse.persistence.sessions.UnitOfWork;
import org.springframework.jdbc.datasource.ConnectionHandle;
@ -31,8 +32,7 @@ import org.springframework.transaction.TransactionException; @@ -31,8 +32,7 @@ import org.springframework.transaction.TransactionException;
/**
* {@link org.springframework.orm.jpa.JpaDialect} implementation for Eclipse
* Persistence Services (EclipseLink). Developed and tested against EclipseLink 2.7;
* backwards-compatible with EclipseLink 2.5 and 2.6 at runtime.
* Persistence Services (EclipseLink). Compatible with EclipseLink 3.0/4.0.
*
* <p>By default, this class acquires an early EclipseLink transaction with an early
* JDBC Connection for non-read-only transactions. This allows for mixing JDBC and
@ -77,22 +77,40 @@ public class EclipseLinkJpaDialect extends DefaultJpaDialect { @@ -77,22 +77,40 @@ public class EclipseLinkJpaDialect extends DefaultJpaDialect {
public Object beginTransaction(EntityManager entityManager, TransactionDefinition definition)
throws PersistenceException, SQLException, TransactionException {
if (definition.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT) {
int currentIsolationLevel = definition.getIsolationLevel();
if (currentIsolationLevel != TransactionDefinition.ISOLATION_DEFAULT) {
// Pass custom isolation level on to EclipseLink's DatabaseLogin configuration
// (since Spring 4.1.2)
// (since Spring 4.1.2 / revised in 5.3.28)
UnitOfWork uow = entityManager.unwrap(UnitOfWork.class);
uow.getLogin().setTransactionIsolation(definition.getIsolationLevel());
DatabaseLogin databaseLogin = uow.getLogin();
// Synchronize on shared DatabaseLogin instance (-> concurrent transactions)
synchronized (databaseLogin) {
int originalIsolationLevel = databaseLogin.getTransactionIsolation();
// Apply current isolation level value, if necessary.
if (currentIsolationLevel != originalIsolationLevel) {
databaseLogin.setTransactionIsolation(currentIsolationLevel);
}
// Transaction begin including enforced JDBC Connection access
// (picking up current isolation level from DatabaseLogin)
entityManager.getTransaction().begin();
uow.beginEarlyTransaction();
entityManager.unwrap(Connection.class);
// Restore original isolation level value, if necessary.
if (currentIsolationLevel != originalIsolationLevel) {
databaseLogin.setTransactionIsolation(originalIsolationLevel);
}
}
}
entityManager.getTransaction().begin();
if (!definition.isReadOnly() && !this.lazyDatabaseTransaction) {
// Begin an early transaction to force EclipseLink to get a JDBC Connection
// so that Spring can manage transactions with JDBC as well as EclipseLink.
entityManager.unwrap(UnitOfWork.class).beginEarlyTransaction();
else {
entityManager.getTransaction().begin();
if (!definition.isReadOnly() && !this.lazyDatabaseTransaction) {
// Begin an early transaction to force EclipseLink to get a JDBC Connection
// so that Spring can manage transactions with JDBC as well as EclipseLink.
entityManager.unwrap(UnitOfWork.class).beginEarlyTransaction();
}
}
return null;
return entityManager;
}
@Override

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

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -30,8 +30,7 @@ import org.springframework.lang.Nullable; @@ -30,8 +30,7 @@ import org.springframework.lang.Nullable;
/**
* {@link org.springframework.orm.jpa.JpaVendorAdapter} implementation for Eclipse
* Persistence Services (EclipseLink). Developed and tested against EclipseLink 2.7;
* backwards-compatible with EclipseLink 2.5 and 2.6 at runtime.
* Persistence Services (EclipseLink). Compatible with EclipseLink 3.0/4.0.
*
* <p>Exposes EclipseLink's persistence provider and EntityManager extension interface,
* and adapts {@link AbstractJpaVendorAdapter}'s common configuration settings.

Loading…
Cancel
Save