HibernateJpaVendorAdapter and LocalSessionFactoryBuilder enforce Hibernate 5.2's connection handling mode DELAYED_ACQUISITION_AND_HOLD

Issue: SPR-14393
This commit is contained in:
Juergen Hoeller 2016-06-24 12:37:31 +02:00
parent 5e08598a2a
commit 711eb99812
4 changed files with 38 additions and 15 deletions

View File

@ -235,7 +235,6 @@ public class HibernateTransactionManager extends AbstractPlatformTransactionMana
* <p>Default is "false". Turning this flag on enforces over-commit holdability on the
* underlying JDBC Connection (if {@link #prepareConnection "prepareConnection"} is on)
* and skips the disconnect-on-completion step.
* @since 4.2
* @see Connection#setHoldability
* @see ResultSet#HOLD_CURSORS_OVER_COMMIT
* @see #disconnectOnCompletion(Session)
@ -689,7 +688,6 @@ public class HibernateTransactionManager extends AbstractPlatformTransactionMana
* <p>The default implementation simply calls {@link Session#disconnect()}.
* Subclasses may override this with a no-op or with fine-tuned disconnection logic.
* @param session the Hibernate Session to disconnect
* @since 4.2
* @see Session#disconnect()
*/
protected void disconnectOnCompletion(Session session) {

View File

@ -139,6 +139,10 @@ public class LocalSessionFactoryBuilder extends Configuration {
if (dataSource != null) {
getProperties().put(Environment.DATASOURCE, dataSource);
}
// Hibernate 5.2: manually enforce connection release mode ON_CLOSE (the former default)
getProperties().put("hibernate.connection.handling_mode", "DELAYED_ACQUISITION_AND_HOLD");
getProperties().put(AvailableSettings.CLASSLOADERS, Collections.singleton(resourceLoader.getClassLoader()));
this.resourcePatternResolver = ResourcePatternUtils.getResourcePatternResolver(resourceLoader);
}
@ -157,6 +161,7 @@ public class LocalSessionFactoryBuilder extends Configuration {
*/
public LocalSessionFactoryBuilder setJtaTransactionManager(Object jtaTransactionManager) {
Assert.notNull(jtaTransactionManager, "Transaction manager reference must not be null");
if (jtaTransactionManager instanceof JtaTransactionManager) {
boolean webspherePresent = ClassUtils.isPresent("com.ibm.wsspi.uow.UOWManager", getClass().getClassLoader());
if (webspherePresent) {
@ -182,6 +187,10 @@ public class LocalSessionFactoryBuilder extends Configuration {
throw new IllegalArgumentException(
"Unknown transaction manager type: " + jtaTransactionManager.getClass().getName());
}
// Hibernate 5.2: manually enforce connection release mode AFTER_STATEMENT (the JTA default)
getProperties().remove("hibernate.connection.handling_mode", "DELAYED_ACQUISITION_AND_RELEASE_AFTER_STATEMENT");
return this;
}

View File

@ -126,7 +126,7 @@ public class HibernateJpaDialect extends DefaultJpaDialect {
}
private boolean prepareConnection = (HibernateConnectionHandle.sessionConnectionMethod == null);
boolean prepareConnection = (HibernateConnectionHandle.sessionConnectionMethod == null);
/**
@ -362,25 +362,15 @@ public class HibernateJpaDialect extends DefaultJpaDialect {
}
if (this.preparedCon != null && this.session.isConnected()) {
Connection conToReset = HibernateConnectionHandle.doGetConnection(this.session);
if (!isEquivalentConnection(conToReset)) {
if (conToReset != this.preparedCon) {
LogFactory.getLog(HibernateJpaDialect.class).warn(
"JDBC Connection to reset not equivalent to originally prepared Connection - please " +
"JDBC Connection to reset not identical to originally prepared Connection - please " +
"make sure to use connection release mode ON_CLOSE (the default) and to run against " +
"Hibernate 4.2+ (or switch HibernateJpaDialect's prepareConnection flag to false");
}
DataSourceUtils.resetConnectionAfterTransaction(conToReset, this.previousIsolationLevel);
}
}
private boolean isEquivalentConnection(Connection con) {
try {
return (con.equals(this.preparedCon) ||
con.unwrap(Connection.class).equals(this.preparedCon.unwrap(Connection.class)));
}
catch (Throwable ex) {
return false;
}
}
}

View File

@ -101,6 +101,27 @@ public class HibernateJpaVendorAdapter extends AbstractJpaVendorAdapter {
}
/**
* Set whether to prepare the underlying JDBC Connection of a transactional
* Hibernate Session, that is, whether to apply a transaction-specific
* isolation level and/or the transaction's read-only flag to the underlying
* JDBC Connection.
* <p>See {@link HibernateJpaDialect#setPrepareConnection(boolean)} for details.
* This is just a convenience flag passed through to {@code HibernateJpaDialect}.
* <p>On Hibernate 5.2, this flag remains {@code true} by default like against
* previous Hibernate versions. The vendor adapter manually enforces Hibernate's
* new connection handling mode {@code DELAYED_ACQUISITION_AND_HOLD} in that case
* unless a user-specified connection handling mode property indicates otherwise;
* switch this flag to {@code false} to avoid that interference.
* @since 4.3.1
* @see #getJpaPropertyMap()
* @see HibernateJpaDialect#beginTransaction
*/
public void setPrepareConnection(boolean prepareConnection) {
this.jpaDialect.setPrepareConnection(prepareConnection);
}
@Override
public PersistenceProvider getPersistenceProvider() {
return this.persistenceProvider;
@ -132,6 +153,11 @@ public class HibernateJpaVendorAdapter extends AbstractJpaVendorAdapter {
jpaProperties.put(Environment.SHOW_SQL, "true");
}
if (this.jpaDialect.prepareConnection) {
// Hibernate 5.2: manually enforce connection release mode ON_CLOSE (the former default)
jpaProperties.put("hibernate.connection.handling_mode", "DELAYED_ACQUISITION_AND_HOLD");
}
return jpaProperties;
}