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
This commit is contained in:
@@ -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
|
||||
* @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();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
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 {
|
||||
|
||||
// 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 {
|
||||
|
||||
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 {
|
||||
|
||||
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 {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user