2424import org .eclipse .persistence .sessions .UnitOfWork ;
2525
2626import org .springframework .jdbc .datasource .ConnectionHandle ;
27- import org .springframework .jdbc .datasource .SimpleConnectionHandle ;
2827import org .springframework .orm .jpa .DefaultJpaDialect ;
2928import org .springframework .transaction .TransactionDefinition ;
3029import org .springframework .transaction .TransactionException ;
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