Skip to content

Commit e4753c9

Browse files
committed
EclipseLinkJpaDialect's getJdbcConnection uses a lazy ConnectionHandle (allowing for deferred internal transaction begin)
Issue: SPR-7753
1 parent bc8e4d3 commit e4753c9

File tree

1 file changed

+43
-11
lines changed

1 file changed

+43
-11
lines changed

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

Lines changed: 43 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@
2424
import org.eclipse.persistence.sessions.UnitOfWork;
2525

2626
import org.springframework.jdbc.datasource.ConnectionHandle;
27-
import org.springframework.jdbc.datasource.SimpleConnectionHandle;
2827
import org.springframework.orm.jpa.DefaultJpaDialect;
2928
import org.springframework.transaction.TransactionDefinition;
3029
import org.springframework.transaction.TransactionException;
@@ -33,14 +32,13 @@
3332
* {@link org.springframework.orm.jpa.JpaDialect} implementation for Eclipse
3433
* Persistence Services (EclipseLink). Developed and tested against EclipseLink 2.4.
3534
*
36-
* <p>By default, this class acquires a EclipseLink transaction to get the JDBC Connection
37-
* early. This allows mixing JDBC and JPA/EclipseLink operations in the same transaction.
38-
* In some cases, this eager acquisition of a transaction/connection may impact
39-
* scalability. In that case, set the "lazyDatabaseTransaction" flag to true if you
40-
* do not require mixing JDBC and JPA operations in the same transaction. Otherwise,
41-
* use a {@link org.springframework.jdbc.datasource.LazyConnectionDataSourceProxy}
42-
* to ensure that the cost of connection acquisition is near zero until code actually
43-
* needs a JDBC Connection.
35+
* <p>By default, this class acquires an early EclipseLink transaction with an early
36+
* JDBC Connection for non-read-only transactions. This allows for mixing JDBC and
37+
* JPA/EclipseLink operations in the same transaction, with cross visibility of
38+
* their impact. If this is not needed, set the "lazyDatabaseTransaction" flag to
39+
* {@code true} or consistently declare all affected transactions as read-only.
40+
* As of Spring 4.1.2, this will reliably avoid early JDBC Connection retrieval
41+
* and therefore keep EclipseLink in shared cache mode.
4442
*
4543
* @author Juergen Hoeller
4644
* @since 2.5.2
@@ -78,6 +76,7 @@ public Object beginTransaction(EntityManager entityManager, TransactionDefinitio
7876

7977
if (definition.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT) {
8078
// Pass custom isolation level on to EclipseLink's DatabaseLogin configuration
79+
// (since Spring 4.1.2)
8180
uow.getLogin().setTransactionIsolation(definition.getIsolationLevel());
8281
}
8382

@@ -96,8 +95,41 @@ public Object beginTransaction(EntityManager entityManager, TransactionDefinitio
9695
public ConnectionHandle getJdbcConnection(EntityManager entityManager, boolean readOnly)
9796
throws PersistenceException, SQLException {
9897

99-
Connection con = entityManager.unwrap(Connection.class);
100-
return (con != null ? new SimpleConnectionHandle(con) : null);
98+
// As of Spring 4.1.2, we're using a custom ConnectionHandle for lazy retrieval
99+
// of the underlying Connection (allowing for deferred internal transaction begin
100+
// within the EclipseLink EntityManager)
101+
return new EclipseLinkConnectionHandle(entityManager);
102+
}
103+
104+
105+
/**
106+
* {@link ConnectionHandle} implementation that lazily fetches an
107+
* EclipseLink-provided Connection on the first {@code getConnection} call -
108+
* which may never come if no application code requests a JDBC Connection.
109+
* This is useful to defer the early transaction begin that obtaining a
110+
* JDBC Connection implies within an EclipseLink EntityManager.
111+
*/
112+
private static class EclipseLinkConnectionHandle implements ConnectionHandle {
113+
114+
private final EntityManager entityManager;
115+
116+
private Connection connection;
117+
118+
public EclipseLinkConnectionHandle(EntityManager entityManager) {
119+
this.entityManager = entityManager;
120+
}
121+
122+
@Override
123+
public Connection getConnection() {
124+
if (this.connection == null) {
125+
this.connection = this.entityManager.unwrap(Connection.class);
126+
}
127+
return this.connection;
128+
}
129+
130+
@Override
131+
public void releaseConnection(Connection con) {
132+
}
101133
}
102134

103135
}

0 commit comments

Comments
 (0)