Browse Source

HibernateJpaDialect logs warning in case of Connection mismatch (e.g. configured release mode other than ON_CLOSE)

Related to that, HibernateTransactionManager specifically checks for active physical connections on reset as of Hibernate 5.

Issue: SPR-13269
Issue: SPR-13002
pull/866/head
Juergen Hoeller 11 years ago
parent
commit
a1107af06f
  1. 25
      spring-orm-hibernate5/src/main/java/org/springframework/orm/hibernate5/HibernateTransactionManager.java
  2. 30
      spring-orm/src/main/java/org/springframework/orm/jpa/vendor/HibernateJpaDialect.java

25
spring-orm-hibernate5/src/main/java/org/springframework/orm/hibernate5/HibernateTransactionManager.java

@ -641,7 +641,7 @@ public class HibernateTransactionManager extends AbstractPlatformTransactionMana @@ -641,7 +641,7 @@ public class HibernateTransactionManager extends AbstractPlatformTransactionMana
}
Session session = txObject.getSessionHolder().getSession();
if (this.prepareConnection && session.isConnected() && isSameConnectionForEntireSession(session)) {
if (this.prepareConnection && isPhysicallyConnected(session)) {
// We're running with connection release mode "on_close": We're able to reset
// the isolation level and/or read-only flag of the JDBC Connection here.
// Else, we need to rely on the connection pool to perform proper cleanup.
@ -704,8 +704,27 @@ public class HibernateTransactionManager extends AbstractPlatformTransactionMana @@ -704,8 +704,27 @@ public class HibernateTransactionManager extends AbstractPlatformTransactionMana
* @see ConnectionReleaseMode#ON_CLOSE
*/
protected boolean isSameConnectionForEntireSession(Session session) {
// TODO: The best we can do is to assume we're safe.
return true;
if (!(session instanceof SessionImplementor)) {
// The best we can do is to assume we're safe.
return true;
}
ConnectionReleaseMode releaseMode =
((SessionImplementor) session).getJdbcCoordinator().getConnectionReleaseMode();
return ConnectionReleaseMode.ON_CLOSE.equals(releaseMode);
}
/**
* Determine whether the given Session is (still) physically connected
* to the database, that is, holds an active JDBC Connection internally.
* @param session the Hibernate Session to check
* @see #isSameConnectionForEntireSession(Session)
*/
protected boolean isPhysicallyConnected(Session session) {
if (!(session instanceof SessionImplementor)) {
// The best we can do is to check whether we're logically connected.
return session.isConnected();
}
return ((SessionImplementor) session).getJdbcCoordinator().getLogicalConnection().isPhysicallyConnected();
}

30
spring-orm/src/main/java/org/springframework/orm/jpa/vendor/HibernateJpaDialect.java vendored

@ -22,6 +22,7 @@ import java.sql.SQLException; @@ -22,6 +22,7 @@ import java.sql.SQLException;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceException;
import org.apache.commons.logging.LogFactory;
import org.hibernate.FlushMode;
import org.hibernate.HibernateException;
import org.hibernate.NonUniqueObjectException;
@ -146,13 +147,12 @@ public class HibernateJpaDialect extends DefaultJpaDialect { @@ -146,13 +147,12 @@ public class HibernateJpaDialect extends DefaultJpaDialect {
boolean isolationLevelNeeded = (definition.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT);
Integer previousIsolationLevel = null;
boolean resetConnection = false;
Connection preparedCon = null;
if (isolationLevelNeeded || definition.isReadOnly()) {
if (this.prepareConnection) {
Connection con = HibernateConnectionHandle.doGetConnection(session);
previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(con, definition);
resetConnection = true;
preparedCon = HibernateConnectionHandle.doGetConnection(session);
previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(preparedCon, definition);
}
else if (isolationLevelNeeded) {
throw new InvalidIsolationLevelException(getClass().getSimpleName() +
@ -167,7 +167,7 @@ public class HibernateJpaDialect extends DefaultJpaDialect { @@ -167,7 +167,7 @@ public class HibernateJpaDialect extends DefaultJpaDialect {
// Adapt flush mode and store previous isolation level, if any.
FlushMode previousFlushMode = prepareFlushMode(session, definition.isReadOnly());
return new SessionTransactionData(session, previousFlushMode, resetConnection, previousIsolationLevel);
return new SessionTransactionData(session, previousFlushMode, preparedCon, previousIsolationLevel);
}
@Override
@ -176,7 +176,7 @@ public class HibernateJpaDialect extends DefaultJpaDialect { @@ -176,7 +176,7 @@ public class HibernateJpaDialect extends DefaultJpaDialect {
Session session = getSession(entityManager);
FlushMode previousFlushMode = prepareFlushMode(session, readOnly);
return new SessionTransactionData(session, previousFlushMode, false, null);
return new SessionTransactionData(session, previousFlushMode, null, null);
}
protected FlushMode prepareFlushMode(Session session, boolean readOnly) throws PersistenceException {
@ -321,15 +321,15 @@ public class HibernateJpaDialect extends DefaultJpaDialect { @@ -321,15 +321,15 @@ public class HibernateJpaDialect extends DefaultJpaDialect {
private final FlushMode previousFlushMode;
private final boolean resetConnection;
private final Connection preparedCon;
private final Integer previousIsolationLevel;
public SessionTransactionData(
Session session, FlushMode previousFlushMode, boolean resetConnection, Integer previousIsolationLevel) {
Session session, FlushMode previousFlushMode, Connection preparedCon, Integer previousIsolationLevel) {
this.session = session;
this.previousFlushMode = previousFlushMode;
this.resetConnection = resetConnection;
this.preparedCon = preparedCon;
this.previousIsolationLevel = previousIsolationLevel;
}
@ -337,9 +337,15 @@ public class HibernateJpaDialect extends DefaultJpaDialect { @@ -337,9 +337,15 @@ public class HibernateJpaDialect extends DefaultJpaDialect {
if (this.previousFlushMode != null) {
this.session.setFlushMode(this.previousFlushMode);
}
if (this.resetConnection && this.session.isConnected()) {
Connection con = HibernateConnectionHandle.doGetConnection(this.session);
DataSourceUtils.resetConnectionAfterTransaction(con, this.previousIsolationLevel);
if (this.preparedCon != null && this.session.isConnected()) {
Connection conToReset = HibernateConnectionHandle.doGetConnection(this.session);
if (conToReset != this.preparedCon) {
LogFactory.getLog(HibernateJpaDialect.class).warn(
"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);
}
}
}

Loading…
Cancel
Save