HibernateJpaDialect/HibernateTransactionManager alignment for 5.2+
See gh-25533
This commit is contained in:
parent
df98d0c661
commit
c99c3142ad
|
@ -458,7 +458,6 @@ public class HibernateTransactionManager extends AbstractPlatformTransactionMana
|
|||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("deprecation")
|
||||
protected void doBegin(Object transaction, TransactionDefinition definition) {
|
||||
HibernateTransactionObject txObject = (HibernateTransactionObject) transaction;
|
||||
|
||||
|
@ -470,7 +469,7 @@ public class HibernateTransactionManager extends AbstractPlatformTransactionMana
|
|||
"on a single DataSource, no matter whether Hibernate or JDBC access.");
|
||||
}
|
||||
|
||||
Session session = null;
|
||||
SessionImplementor session = null;
|
||||
|
||||
try {
|
||||
if (!txObject.hasSessionHolder() || txObject.getSessionHolder().isSynchronizedWithTransaction()) {
|
||||
|
@ -487,17 +486,18 @@ public class HibernateTransactionManager extends AbstractPlatformTransactionMana
|
|||
txObject.setSession(newSession);
|
||||
}
|
||||
|
||||
session = txObject.getSessionHolder().getSession();
|
||||
session = txObject.getSessionHolder().getSession().unwrap(SessionImplementor.class);
|
||||
|
||||
boolean holdabilityNeeded = this.allowResultAccessAfterCompletion && !txObject.isNewSession();
|
||||
boolean isolationLevelNeeded = (definition.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT);
|
||||
if (holdabilityNeeded || isolationLevelNeeded || definition.isReadOnly()) {
|
||||
if (this.prepareConnection && isSameConnectionForEntireSession(session)) {
|
||||
if (this.prepareConnection && ConnectionReleaseMode.ON_CLOSE.equals(
|
||||
session.getJdbcCoordinator().getLogicalConnection().getConnectionHandlingMode().getReleaseMode())) {
|
||||
// We're allowed to change the transaction settings of the JDBC Connection.
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Preparing JDBC Connection of Hibernate Session [" + session + "]");
|
||||
}
|
||||
Connection con = ((SessionImplementor) session).connection();
|
||||
Connection con = session.connection();
|
||||
Integer previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(con, definition);
|
||||
txObject.setPreviousIsolationLevel(previousIsolationLevel);
|
||||
txObject.setReadOnly(definition.isReadOnly());
|
||||
|
@ -508,6 +508,7 @@ public class HibernateTransactionManager extends AbstractPlatformTransactionMana
|
|||
con.setHoldability(ResultSet.HOLD_CURSORS_OVER_COMMIT);
|
||||
}
|
||||
}
|
||||
txObject.connectionPrepared();
|
||||
}
|
||||
else {
|
||||
// Not allowed to change the transaction settings of the JDBC Connection.
|
||||
|
@ -516,7 +517,7 @@ public class HibernateTransactionManager extends AbstractPlatformTransactionMana
|
|||
throw new InvalidIsolationLevelException(
|
||||
"HibernateTransactionManager is not allowed to support custom isolation levels: " +
|
||||
"make sure that its 'prepareConnection' flag is on (the default) and that the " +
|
||||
"Hibernate connection release mode is set to 'on_close' (the default for JDBC).");
|
||||
"Hibernate connection release mode is set to ON_CLOSE.");
|
||||
}
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Not preparing JDBC Connection of Hibernate Session [" + session + "]");
|
||||
|
@ -526,7 +527,7 @@ public class HibernateTransactionManager extends AbstractPlatformTransactionMana
|
|||
|
||||
if (definition.isReadOnly() && txObject.isNewSession()) {
|
||||
// Just set to MANUAL in case of a new Session for this transaction.
|
||||
session.setFlushMode(FlushMode.MANUAL);
|
||||
session.setHibernateFlushMode(FlushMode.MANUAL);
|
||||
// As of 5.1, we're also setting Hibernate's read-only entity mode by default.
|
||||
session.setDefaultReadOnly(true);
|
||||
}
|
||||
|
@ -535,7 +536,7 @@ public class HibernateTransactionManager extends AbstractPlatformTransactionMana
|
|||
// We need AUTO or COMMIT for a non-read-only transaction.
|
||||
FlushMode flushMode = session.getHibernateFlushMode();
|
||||
if (FlushMode.MANUAL.equals(flushMode)) {
|
||||
session.setFlushMode(FlushMode.AUTO);
|
||||
session.setHibernateFlushMode(FlushMode.AUTO);
|
||||
txObject.getSessionHolder().setPreviousFlushMode(flushMode);
|
||||
}
|
||||
}
|
||||
|
@ -561,8 +562,7 @@ public class HibernateTransactionManager extends AbstractPlatformTransactionMana
|
|||
|
||||
// Register the Hibernate Session's JDBC Connection for the DataSource, if set.
|
||||
if (getDataSource() != null) {
|
||||
SessionImplementor sessionImpl = (SessionImplementor) session;
|
||||
ConnectionHolder conHolder = new ConnectionHolder(sessionImpl::connection);
|
||||
ConnectionHolder conHolder = new ConnectionHolder(session::connection);
|
||||
if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) {
|
||||
conHolder.setTimeoutInSeconds(timeout);
|
||||
}
|
||||
|
@ -704,7 +704,6 @@ public class HibernateTransactionManager extends AbstractPlatformTransactionMana
|
|||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("deprecation")
|
||||
protected void doCleanupAfterCompletion(Object transaction) {
|
||||
HibernateTransactionObject txObject = (HibernateTransactionObject) transaction;
|
||||
|
||||
|
@ -718,13 +717,14 @@ public class HibernateTransactionManager extends AbstractPlatformTransactionMana
|
|||
TransactionSynchronizationManager.unbindResource(getDataSource());
|
||||
}
|
||||
|
||||
Session session = txObject.getSessionHolder().getSession();
|
||||
if (this.prepareConnection && isPhysicallyConnected(session)) {
|
||||
// We're running with connection release mode "on_close": We're able to reset
|
||||
SessionImplementor session = txObject.getSessionHolder().getSession().unwrap(SessionImplementor.class);
|
||||
if (txObject.needsConnectionReset() &&
|
||||
session.getJdbcCoordinator().getLogicalConnection().isPhysicallyConnected()) {
|
||||
// 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.
|
||||
try {
|
||||
Connection con = ((SessionImplementor) session).connection();
|
||||
Connection con = session.connection();
|
||||
Integer previousHoldability = txObject.getPreviousHoldability();
|
||||
if (previousHoldability != null) {
|
||||
con.setHoldability(previousHoldability);
|
||||
|
@ -751,7 +751,7 @@ public class HibernateTransactionManager extends AbstractPlatformTransactionMana
|
|||
logger.debug("Not closing pre-bound Hibernate Session [" + session + "] after transaction");
|
||||
}
|
||||
if (txObject.getSessionHolder().getPreviousFlushMode() != null) {
|
||||
session.setFlushMode(txObject.getSessionHolder().getPreviousFlushMode());
|
||||
session.setHibernateFlushMode(txObject.getSessionHolder().getPreviousFlushMode());
|
||||
}
|
||||
if (!this.allowResultAccessAfterCompletion && !this.hibernateManagedSession) {
|
||||
disconnectOnCompletion(session);
|
||||
|
@ -772,41 +772,6 @@ public class HibernateTransactionManager extends AbstractPlatformTransactionMana
|
|||
session.disconnect();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether the given Hibernate Session will always hold the same
|
||||
* JDBC Connection. This is used to check whether the transaction manager
|
||||
* can safely prepare and clean up the JDBC Connection used for a transaction.
|
||||
* <p>The default implementation checks the Session's connection release mode
|
||||
* to be "on_close".
|
||||
* @param session the Hibernate Session to check
|
||||
* @see ConnectionReleaseMode#ON_CLOSE
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
protected boolean isSameConnectionForEntireSession(Session session) {
|
||||
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();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Convert the given HibernateException to an appropriate exception
|
||||
* from the {@code org.springframework.dao} hierarchy.
|
||||
|
@ -834,6 +799,8 @@ public class HibernateTransactionManager extends AbstractPlatformTransactionMana
|
|||
|
||||
private boolean newSession;
|
||||
|
||||
private boolean needsConnectionReset;
|
||||
|
||||
@Nullable
|
||||
private Integer previousHoldability;
|
||||
|
||||
|
@ -872,6 +839,14 @@ public class HibernateTransactionManager extends AbstractPlatformTransactionMana
|
|||
return this.newSession;
|
||||
}
|
||||
|
||||
public void connectionPrepared() {
|
||||
this.needsConnectionReset = true;
|
||||
}
|
||||
|
||||
public boolean needsConnectionReset() {
|
||||
return this.needsConnectionReset;
|
||||
}
|
||||
|
||||
public void setPreviousHoldability(@Nullable Integer previousHoldability) {
|
||||
this.previousHoldability = previousHoldability;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -38,11 +38,10 @@ public class SpringJtaSessionContext extends JTASessionContext {
|
|||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("deprecation")
|
||||
protected Session buildOrObtainSession() {
|
||||
Session session = super.buildOrObtainSession();
|
||||
if (TransactionSynchronizationManager.isCurrentTransactionReadOnly()) {
|
||||
session.setFlushMode(FlushMode.MANUAL);
|
||||
session.setHibernateFlushMode(FlushMode.MANUAL);
|
||||
}
|
||||
return session;
|
||||
}
|
||||
|
|
|
@ -80,7 +80,6 @@ public class SpringSessionContext implements CurrentSessionContext {
|
|||
* Retrieve the Spring-managed Session for the current thread, if any.
|
||||
*/
|
||||
@Override
|
||||
@SuppressWarnings("deprecation")
|
||||
public Session currentSession() throws HibernateException {
|
||||
Object value = TransactionSynchronizationManager.getResource(this.sessionFactory);
|
||||
if (value instanceof Session) {
|
||||
|
@ -100,7 +99,7 @@ public class SpringSessionContext implements CurrentSessionContext {
|
|||
FlushMode flushMode = session.getHibernateFlushMode();
|
||||
if (flushMode.equals(FlushMode.MANUAL) &&
|
||||
!TransactionSynchronizationManager.isCurrentTransactionReadOnly()) {
|
||||
session.setFlushMode(FlushMode.AUTO);
|
||||
session.setHibernateFlushMode(FlushMode.AUTO);
|
||||
sessionHolder.setPreviousFlushMode(flushMode);
|
||||
}
|
||||
}
|
||||
|
@ -130,7 +129,7 @@ public class SpringSessionContext implements CurrentSessionContext {
|
|||
if (TransactionSynchronizationManager.isSynchronizationActive()) {
|
||||
Session session = this.sessionFactory.openSession();
|
||||
if (TransactionSynchronizationManager.isCurrentTransactionReadOnly()) {
|
||||
session.setFlushMode(FlushMode.MANUAL);
|
||||
session.setHibernateFlushMode(FlushMode.MANUAL);
|
||||
}
|
||||
SessionHolder sessionHolder = new SessionHolder(session);
|
||||
TransactionSynchronizationManager.registerSynchronization(
|
||||
|
|
|
@ -98,13 +98,12 @@ public class SpringSessionSynchronization implements TransactionSynchronization,
|
|||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("deprecation")
|
||||
public void beforeCompletion() {
|
||||
try {
|
||||
Session session = this.sessionHolder.getSession();
|
||||
if (this.sessionHolder.getPreviousFlushMode() != null) {
|
||||
// In case of pre-bound Session, restore previous flush mode.
|
||||
session.setFlushMode(this.sessionHolder.getPreviousFlushMode());
|
||||
session.setHibernateFlushMode(this.sessionHolder.getPreviousFlushMode());
|
||||
}
|
||||
// Eagerly disconnect the Session here, to make release mode "on_close" work nicely.
|
||||
session.disconnect();
|
||||
|
|
|
@ -204,11 +204,10 @@ public class OpenSessionInViewFilter extends OncePerRequestFilter {
|
|||
* @throws DataAccessResourceFailureException if the Session could not be created
|
||||
* @see FlushMode#MANUAL
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
protected Session openSession(SessionFactory sessionFactory) throws DataAccessResourceFailureException {
|
||||
try {
|
||||
Session session = sessionFactory.openSession();
|
||||
session.setFlushMode(FlushMode.MANUAL);
|
||||
session.setHibernateFlushMode(FlushMode.MANUAL);
|
||||
return session;
|
||||
}
|
||||
catch (HibernateException ex) {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -186,11 +186,10 @@ public class OpenSessionInViewInterceptor implements AsyncWebRequestInterceptor
|
|||
* @throws DataAccessResourceFailureException if the Session could not be created
|
||||
* @see FlushMode#MANUAL
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
protected Session openSession() throws DataAccessResourceFailureException {
|
||||
try {
|
||||
Session session = obtainSessionFactory().openSession();
|
||||
session.setFlushMode(FlushMode.MANUAL);
|
||||
session.setHibernateFlushMode(FlushMode.MANUAL);
|
||||
return session;
|
||||
}
|
||||
catch (HibernateException ex) {
|
||||
|
|
|
@ -111,13 +111,12 @@ public class OpenSessionInterceptor implements MethodInterceptor, InitializingBe
|
|||
* @since 5.0
|
||||
* @see FlushMode#MANUAL
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
protected Session openSession(SessionFactory sessionFactory) throws DataAccessResourceFailureException {
|
||||
Session session = openSession();
|
||||
if (session == null) {
|
||||
try {
|
||||
session = sessionFactory.openSession();
|
||||
session.setFlushMode(FlushMode.MANUAL);
|
||||
session.setHibernateFlushMode(FlushMode.MANUAL);
|
||||
}
|
||||
catch (HibernateException ex) {
|
||||
throw new DataAccessResourceFailureException("Could not open Hibernate Session", ex);
|
||||
|
|
|
@ -16,14 +16,13 @@
|
|||
|
||||
package org.springframework.orm.jpa.vendor;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.persistence.PersistenceException;
|
||||
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.hibernate.ConnectionReleaseMode;
|
||||
import org.hibernate.FlushMode;
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.JDBCException;
|
||||
|
@ -43,6 +42,7 @@ import org.hibernate.UnresolvableObjectException;
|
|||
import org.hibernate.WrongClassException;
|
||||
import org.hibernate.dialect.lock.OptimisticEntityLockException;
|
||||
import org.hibernate.dialect.lock.PessimisticEntityLockException;
|
||||
import org.hibernate.engine.spi.SessionImplementor;
|
||||
import org.hibernate.exception.ConstraintViolationException;
|
||||
import org.hibernate.exception.DataException;
|
||||
import org.hibernate.exception.JDBCConnectionException;
|
||||
|
@ -71,12 +71,10 @@ import org.springframework.transaction.InvalidIsolationLevelException;
|
|||
import org.springframework.transaction.TransactionDefinition;
|
||||
import org.springframework.transaction.TransactionException;
|
||||
import org.springframework.transaction.support.ResourceTransactionDefinition;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
/**
|
||||
* {@link org.springframework.orm.jpa.JpaDialect} implementation for
|
||||
* Hibernate EntityManager. Developed against Hibernate 5.1/5.2/5.3/5.4.
|
||||
* Hibernate EntityManager. Developed against Hibernate 5.2/5.3/5.4.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @author Costin Leau
|
||||
|
@ -88,27 +86,6 @@ import org.springframework.util.ReflectionUtils;
|
|||
@SuppressWarnings("serial")
|
||||
public class HibernateJpaDialect extends DefaultJpaDialect {
|
||||
|
||||
private static Method getFlushMode;
|
||||
|
||||
static {
|
||||
try {
|
||||
// Hibernate 5.2+ getHibernateFlushMode()
|
||||
getFlushMode = Session.class.getMethod("getHibernateFlushMode");
|
||||
}
|
||||
catch (NoSuchMethodException ex) {
|
||||
try {
|
||||
// Classic Hibernate getFlushMode() with FlushMode return type
|
||||
getFlushMode = Session.class.getMethod("getFlushMode");
|
||||
}
|
||||
catch (NoSuchMethodException ex2) {
|
||||
throw new IllegalStateException("No compatible Hibernate getFlushMode signature found", ex2);
|
||||
}
|
||||
}
|
||||
// Check that it is the Hibernate FlushMode type, not JPA's...
|
||||
Assert.state(FlushMode.class == getFlushMode.getReturnType(), "Could not find Hibernate getFlushMode method");
|
||||
}
|
||||
|
||||
|
||||
boolean prepareConnection = true;
|
||||
|
||||
@Nullable
|
||||
|
@ -159,7 +136,7 @@ public class HibernateJpaDialect extends DefaultJpaDialect {
|
|||
public Object beginTransaction(EntityManager entityManager, TransactionDefinition definition)
|
||||
throws PersistenceException, SQLException, TransactionException {
|
||||
|
||||
Session session = getSession(entityManager);
|
||||
SessionImplementor session = getSession(entityManager);
|
||||
|
||||
if (definition.getTimeout() != TransactionDefinition.TIMEOUT_DEFAULT) {
|
||||
session.getTransaction().setTimeout(definition.getTimeout());
|
||||
|
@ -170,13 +147,16 @@ public class HibernateJpaDialect extends DefaultJpaDialect {
|
|||
Connection preparedCon = null;
|
||||
|
||||
if (isolationLevelNeeded || definition.isReadOnly()) {
|
||||
if (this.prepareConnection) {
|
||||
preparedCon = HibernateConnectionHandle.doGetConnection(session);
|
||||
if (this.prepareConnection && ConnectionReleaseMode.ON_CLOSE.equals(
|
||||
session.getJdbcCoordinator().getLogicalConnection().getConnectionHandlingMode().getReleaseMode())) {
|
||||
preparedCon = session.connection();
|
||||
previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(preparedCon, definition);
|
||||
}
|
||||
else if (isolationLevelNeeded) {
|
||||
throw new InvalidIsolationLevelException(getClass().getSimpleName() +
|
||||
" does not support custom isolation levels since the 'prepareConnection' flag is off.");
|
||||
throw new InvalidIsolationLevelException(
|
||||
"HibernateJpaDialect is not allowed to support custom isolation levels: " +
|
||||
"make sure that its 'prepareConnection' flag is on (the default) and that the " +
|
||||
"Hibernate connection release mode is set to ON_CLOSE.");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -195,34 +175,32 @@ public class HibernateJpaDialect extends DefaultJpaDialect {
|
|||
}
|
||||
}
|
||||
return new SessionTransactionData(
|
||||
session, previousFlushMode, preparedCon, previousIsolationLevel, definition.isReadOnly());
|
||||
session, previousFlushMode, (preparedCon != null), previousIsolationLevel, definition.isReadOnly());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object prepareTransaction(EntityManager entityManager, boolean readOnly, @Nullable String name)
|
||||
throws PersistenceException {
|
||||
|
||||
Session session = getSession(entityManager);
|
||||
SessionImplementor session = getSession(entityManager);
|
||||
FlushMode previousFlushMode = prepareFlushMode(session, readOnly);
|
||||
return new SessionTransactionData(session, previousFlushMode, null, null, readOnly);
|
||||
return new SessionTransactionData(session, previousFlushMode, false, null, readOnly);
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@Nullable
|
||||
protected FlushMode prepareFlushMode(Session session, boolean readOnly) throws PersistenceException {
|
||||
FlushMode flushMode = (FlushMode) ReflectionUtils.invokeMethod(getFlushMode, session);
|
||||
Assert.state(flushMode != null, "No FlushMode from Session");
|
||||
FlushMode flushMode = session.getHibernateFlushMode();
|
||||
if (readOnly) {
|
||||
// We should suppress flushing for a read-only transaction.
|
||||
if (!flushMode.equals(FlushMode.MANUAL)) {
|
||||
session.setFlushMode(FlushMode.MANUAL);
|
||||
session.setHibernateFlushMode(FlushMode.MANUAL);
|
||||
return flushMode;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// We need AUTO or COMMIT for a non-read-only transaction.
|
||||
if (flushMode.lessThan(FlushMode.COMMIT)) {
|
||||
session.setFlushMode(FlushMode.AUTO);
|
||||
session.setHibernateFlushMode(FlushMode.AUTO);
|
||||
return flushMode;
|
||||
}
|
||||
}
|
||||
|
@ -241,7 +219,7 @@ public class HibernateJpaDialect extends DefaultJpaDialect {
|
|||
public ConnectionHandle getJdbcConnection(EntityManager entityManager, boolean readOnly)
|
||||
throws PersistenceException, SQLException {
|
||||
|
||||
Session session = getSession(entityManager);
|
||||
SessionImplementor session = getSession(entityManager);
|
||||
return new HibernateConnectionHandle(session);
|
||||
}
|
||||
|
||||
|
@ -353,32 +331,31 @@ public class HibernateJpaDialect extends DefaultJpaDialect {
|
|||
return new JpaSystemException(ex);
|
||||
}
|
||||
|
||||
protected Session getSession(EntityManager entityManager) {
|
||||
return entityManager.unwrap(Session.class);
|
||||
protected SessionImplementor getSession(EntityManager entityManager) {
|
||||
return entityManager.unwrap(SessionImplementor.class);
|
||||
}
|
||||
|
||||
|
||||
private static class SessionTransactionData {
|
||||
|
||||
private final Session session;
|
||||
private final SessionImplementor session;
|
||||
|
||||
@Nullable
|
||||
private final FlushMode previousFlushMode;
|
||||
|
||||
@Nullable
|
||||
private final Connection preparedCon;
|
||||
private final boolean needsConnectionReset;
|
||||
|
||||
@Nullable
|
||||
private final Integer previousIsolationLevel;
|
||||
|
||||
private final boolean readOnly;
|
||||
|
||||
public SessionTransactionData(Session session, @Nullable FlushMode previousFlushMode,
|
||||
@Nullable Connection preparedCon, @Nullable Integer previousIsolationLevel, boolean readOnly) {
|
||||
public SessionTransactionData(SessionImplementor session, @Nullable FlushMode previousFlushMode,
|
||||
boolean connectionPrepared, @Nullable Integer previousIsolationLevel, boolean readOnly) {
|
||||
|
||||
this.session = session;
|
||||
this.previousFlushMode = previousFlushMode;
|
||||
this.preparedCon = preparedCon;
|
||||
this.needsConnectionReset = connectionPrepared;
|
||||
this.previousIsolationLevel = previousIsolationLevel;
|
||||
this.readOnly = readOnly;
|
||||
}
|
||||
|
@ -388,14 +365,9 @@ public class HibernateJpaDialect extends DefaultJpaDialect {
|
|||
if (this.previousFlushMode != null) {
|
||||
this.session.setFlushMode(this.previousFlushMode);
|
||||
}
|
||||
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");
|
||||
}
|
||||
if (this.needsConnectionReset &&
|
||||
this.session.getJdbcCoordinator().getLogicalConnection().isPhysicallyConnected()) {
|
||||
Connection conToReset = this.session.connection();
|
||||
DataSourceUtils.resetConnectionAfterTransaction(
|
||||
conToReset, this.previousIsolationLevel, this.readOnly);
|
||||
}
|
||||
|
@ -405,35 +377,15 @@ public class HibernateJpaDialect extends DefaultJpaDialect {
|
|||
|
||||
private static class HibernateConnectionHandle implements ConnectionHandle {
|
||||
|
||||
@Nullable
|
||||
private static volatile Method connectionMethodToUse;
|
||||
private final SessionImplementor session;
|
||||
|
||||
private final Session session;
|
||||
|
||||
public HibernateConnectionHandle(Session session) {
|
||||
public HibernateConnectionHandle(SessionImplementor session) {
|
||||
this.session = session;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Connection getConnection() {
|
||||
return doGetConnection(this.session);
|
||||
}
|
||||
|
||||
public static Connection doGetConnection(Session session) {
|
||||
try {
|
||||
Method methodToUse = connectionMethodToUse;
|
||||
if (methodToUse == null) {
|
||||
// Reflective lookup to find SessionImpl's connection() method on Hibernate 4.x/5.x
|
||||
methodToUse = session.getClass().getMethod("connection");
|
||||
connectionMethodToUse = methodToUse;
|
||||
}
|
||||
Connection con = (Connection) ReflectionUtils.invokeMethod(methodToUse, session);
|
||||
Assert.state(con != null, "No Connection from Session");
|
||||
return con;
|
||||
}
|
||||
catch (NoSuchMethodException ex) {
|
||||
throw new IllegalStateException("Cannot find connection() method on Hibernate Session", ex);
|
||||
}
|
||||
return this.session.connection();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue