Skip to content

Commit c99c314

Browse files
committed
HibernateJpaDialect/HibernateTransactionManager alignment for 5.2+
See gh-25533
1 parent df98d0c commit c99c314

8 files changed

+66
-145
lines changed

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

+26-51
Original file line numberDiff line numberDiff line change
@@ -458,7 +458,6 @@ protected boolean isExistingTransaction(Object transaction) {
458458
}
459459

460460
@Override
461-
@SuppressWarnings("deprecation")
462461
protected void doBegin(Object transaction, TransactionDefinition definition) {
463462
HibernateTransactionObject txObject = (HibernateTransactionObject) transaction;
464463

@@ -470,7 +469,7 @@ protected void doBegin(Object transaction, TransactionDefinition definition) {
470469
"on a single DataSource, no matter whether Hibernate or JDBC access.");
471470
}
472471

473-
Session session = null;
472+
SessionImplementor session = null;
474473

475474
try {
476475
if (!txObject.hasSessionHolder() || txObject.getSessionHolder().isSynchronizedWithTransaction()) {
@@ -487,17 +486,18 @@ protected void doBegin(Object transaction, TransactionDefinition definition) {
487486
txObject.setSession(newSession);
488487
}
489488

490-
session = txObject.getSessionHolder().getSession();
489+
session = txObject.getSessionHolder().getSession().unwrap(SessionImplementor.class);
491490

492491
boolean holdabilityNeeded = this.allowResultAccessAfterCompletion && !txObject.isNewSession();
493492
boolean isolationLevelNeeded = (definition.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT);
494493
if (holdabilityNeeded || isolationLevelNeeded || definition.isReadOnly()) {
495-
if (this.prepareConnection && isSameConnectionForEntireSession(session)) {
494+
if (this.prepareConnection && ConnectionReleaseMode.ON_CLOSE.equals(
495+
session.getJdbcCoordinator().getLogicalConnection().getConnectionHandlingMode().getReleaseMode())) {
496496
// We're allowed to change the transaction settings of the JDBC Connection.
497497
if (logger.isDebugEnabled()) {
498498
logger.debug("Preparing JDBC Connection of Hibernate Session [" + session + "]");
499499
}
500-
Connection con = ((SessionImplementor) session).connection();
500+
Connection con = session.connection();
501501
Integer previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(con, definition);
502502
txObject.setPreviousIsolationLevel(previousIsolationLevel);
503503
txObject.setReadOnly(definition.isReadOnly());
@@ -508,6 +508,7 @@ protected void doBegin(Object transaction, TransactionDefinition definition) {
508508
con.setHoldability(ResultSet.HOLD_CURSORS_OVER_COMMIT);
509509
}
510510
}
511+
txObject.connectionPrepared();
511512
}
512513
else {
513514
// Not allowed to change the transaction settings of the JDBC Connection.
@@ -516,7 +517,7 @@ protected void doBegin(Object transaction, TransactionDefinition definition) {
516517
throw new InvalidIsolationLevelException(
517518
"HibernateTransactionManager is not allowed to support custom isolation levels: " +
518519
"make sure that its 'prepareConnection' flag is on (the default) and that the " +
519-
"Hibernate connection release mode is set to 'on_close' (the default for JDBC).");
520+
"Hibernate connection release mode is set to ON_CLOSE.");
520521
}
521522
if (logger.isDebugEnabled()) {
522523
logger.debug("Not preparing JDBC Connection of Hibernate Session [" + session + "]");
@@ -526,7 +527,7 @@ protected void doBegin(Object transaction, TransactionDefinition definition) {
526527

527528
if (definition.isReadOnly() && txObject.isNewSession()) {
528529
// Just set to MANUAL in case of a new Session for this transaction.
529-
session.setFlushMode(FlushMode.MANUAL);
530+
session.setHibernateFlushMode(FlushMode.MANUAL);
530531
// As of 5.1, we're also setting Hibernate's read-only entity mode by default.
531532
session.setDefaultReadOnly(true);
532533
}
@@ -535,7 +536,7 @@ protected void doBegin(Object transaction, TransactionDefinition definition) {
535536
// We need AUTO or COMMIT for a non-read-only transaction.
536537
FlushMode flushMode = session.getHibernateFlushMode();
537538
if (FlushMode.MANUAL.equals(flushMode)) {
538-
session.setFlushMode(FlushMode.AUTO);
539+
session.setHibernateFlushMode(FlushMode.AUTO);
539540
txObject.getSessionHolder().setPreviousFlushMode(flushMode);
540541
}
541542
}
@@ -561,8 +562,7 @@ protected void doBegin(Object transaction, TransactionDefinition definition) {
561562

562563
// Register the Hibernate Session's JDBC Connection for the DataSource, if set.
563564
if (getDataSource() != null) {
564-
SessionImplementor sessionImpl = (SessionImplementor) session;
565-
ConnectionHolder conHolder = new ConnectionHolder(sessionImpl::connection);
565+
ConnectionHolder conHolder = new ConnectionHolder(session::connection);
566566
if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) {
567567
conHolder.setTimeoutInSeconds(timeout);
568568
}
@@ -704,7 +704,6 @@ protected void doSetRollbackOnly(DefaultTransactionStatus status) {
704704
}
705705

706706
@Override
707-
@SuppressWarnings("deprecation")
708707
protected void doCleanupAfterCompletion(Object transaction) {
709708
HibernateTransactionObject txObject = (HibernateTransactionObject) transaction;
710709

@@ -718,13 +717,14 @@ protected void doCleanupAfterCompletion(Object transaction) {
718717
TransactionSynchronizationManager.unbindResource(getDataSource());
719718
}
720719

721-
Session session = txObject.getSessionHolder().getSession();
722-
if (this.prepareConnection && isPhysicallyConnected(session)) {
723-
// We're running with connection release mode "on_close": We're able to reset
720+
SessionImplementor session = txObject.getSessionHolder().getSession().unwrap(SessionImplementor.class);
721+
if (txObject.needsConnectionReset() &&
722+
session.getJdbcCoordinator().getLogicalConnection().isPhysicallyConnected()) {
723+
// We're running with connection release mode ON_CLOSE: We're able to reset
724724
// the isolation level and/or read-only flag of the JDBC Connection here.
725725
// Else, we need to rely on the connection pool to perform proper cleanup.
726726
try {
727-
Connection con = ((SessionImplementor) session).connection();
727+
Connection con = session.connection();
728728
Integer previousHoldability = txObject.getPreviousHoldability();
729729
if (previousHoldability != null) {
730730
con.setHoldability(previousHoldability);
@@ -751,7 +751,7 @@ protected void doCleanupAfterCompletion(Object transaction) {
751751
logger.debug("Not closing pre-bound Hibernate Session [" + session + "] after transaction");
752752
}
753753
if (txObject.getSessionHolder().getPreviousFlushMode() != null) {
754-
session.setFlushMode(txObject.getSessionHolder().getPreviousFlushMode());
754+
session.setHibernateFlushMode(txObject.getSessionHolder().getPreviousFlushMode());
755755
}
756756
if (!this.allowResultAccessAfterCompletion && !this.hibernateManagedSession) {
757757
disconnectOnCompletion(session);
@@ -772,41 +772,6 @@ protected void disconnectOnCompletion(Session session) {
772772
session.disconnect();
773773
}
774774

775-
/**
776-
* Return whether the given Hibernate Session will always hold the same
777-
* JDBC Connection. This is used to check whether the transaction manager
778-
* can safely prepare and clean up the JDBC Connection used for a transaction.
779-
* <p>The default implementation checks the Session's connection release mode
780-
* to be "on_close".
781-
* @param session the Hibernate Session to check
782-
* @see ConnectionReleaseMode#ON_CLOSE
783-
*/
784-
@SuppressWarnings("deprecation")
785-
protected boolean isSameConnectionForEntireSession(Session session) {
786-
if (!(session instanceof SessionImplementor)) {
787-
// The best we can do is to assume we're safe.
788-
return true;
789-
}
790-
ConnectionReleaseMode releaseMode =
791-
((SessionImplementor) session).getJdbcCoordinator().getConnectionReleaseMode();
792-
return ConnectionReleaseMode.ON_CLOSE.equals(releaseMode);
793-
}
794-
795-
/**
796-
* Determine whether the given Session is (still) physically connected
797-
* to the database, that is, holds an active JDBC Connection internally.
798-
* @param session the Hibernate Session to check
799-
* @see #isSameConnectionForEntireSession(Session)
800-
*/
801-
protected boolean isPhysicallyConnected(Session session) {
802-
if (!(session instanceof SessionImplementor)) {
803-
// The best we can do is to check whether we're logically connected.
804-
return session.isConnected();
805-
}
806-
return ((SessionImplementor) session).getJdbcCoordinator().getLogicalConnection().isPhysicallyConnected();
807-
}
808-
809-
810775
/**
811776
* Convert the given HibernateException to an appropriate exception
812777
* from the {@code org.springframework.dao} hierarchy.
@@ -834,6 +799,8 @@ private class HibernateTransactionObject extends JdbcTransactionObjectSupport {
834799

835800
private boolean newSession;
836801

802+
private boolean needsConnectionReset;
803+
837804
@Nullable
838805
private Integer previousHoldability;
839806

@@ -872,6 +839,14 @@ public boolean isNewSession() {
872839
return this.newSession;
873840
}
874841

842+
public void connectionPrepared() {
843+
this.needsConnectionReset = true;
844+
}
845+
846+
public boolean needsConnectionReset() {
847+
return this.needsConnectionReset;
848+
}
849+
875850
public void setPreviousHoldability(@Nullable Integer previousHoldability) {
876851
this.previousHoldability = previousHoldability;
877852
}

spring-orm/src/main/java/org/springframework/orm/hibernate5/SpringJtaSessionContext.java

+2-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2016 the original author or authors.
2+
* Copyright 2002-2020 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -38,11 +38,10 @@ public SpringJtaSessionContext(SessionFactoryImplementor factory) {
3838
}
3939

4040
@Override
41-
@SuppressWarnings("deprecation")
4241
protected Session buildOrObtainSession() {
4342
Session session = super.buildOrObtainSession();
4443
if (TransactionSynchronizationManager.isCurrentTransactionReadOnly()) {
45-
session.setFlushMode(FlushMode.MANUAL);
44+
session.setHibernateFlushMode(FlushMode.MANUAL);
4645
}
4746
return session;
4847
}

spring-orm/src/main/java/org/springframework/orm/hibernate5/SpringSessionContext.java

+2-3
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,6 @@ public SpringSessionContext(SessionFactoryImplementor sessionFactory) {
8080
* Retrieve the Spring-managed Session for the current thread, if any.
8181
*/
8282
@Override
83-
@SuppressWarnings("deprecation")
8483
public Session currentSession() throws HibernateException {
8584
Object value = TransactionSynchronizationManager.getResource(this.sessionFactory);
8685
if (value instanceof Session) {
@@ -100,7 +99,7 @@ else if (value instanceof SessionHolder) {
10099
FlushMode flushMode = session.getHibernateFlushMode();
101100
if (flushMode.equals(FlushMode.MANUAL) &&
102101
!TransactionSynchronizationManager.isCurrentTransactionReadOnly()) {
103-
session.setFlushMode(FlushMode.AUTO);
102+
session.setHibernateFlushMode(FlushMode.AUTO);
104103
sessionHolder.setPreviousFlushMode(flushMode);
105104
}
106105
}
@@ -130,7 +129,7 @@ else if (value instanceof EntityManagerHolder) {
130129
if (TransactionSynchronizationManager.isSynchronizationActive()) {
131130
Session session = this.sessionFactory.openSession();
132131
if (TransactionSynchronizationManager.isCurrentTransactionReadOnly()) {
133-
session.setFlushMode(FlushMode.MANUAL);
132+
session.setHibernateFlushMode(FlushMode.MANUAL);
134133
}
135134
SessionHolder sessionHolder = new SessionHolder(session);
136135
TransactionSynchronizationManager.registerSynchronization(

spring-orm/src/main/java/org/springframework/orm/hibernate5/SpringSessionSynchronization.java

+1-2
Original file line numberDiff line numberDiff line change
@@ -98,13 +98,12 @@ public void beforeCommit(boolean readOnly) throws DataAccessException {
9898
}
9999

100100
@Override
101-
@SuppressWarnings("deprecation")
102101
public void beforeCompletion() {
103102
try {
104103
Session session = this.sessionHolder.getSession();
105104
if (this.sessionHolder.getPreviousFlushMode() != null) {
106105
// In case of pre-bound Session, restore previous flush mode.
107-
session.setFlushMode(this.sessionHolder.getPreviousFlushMode());
106+
session.setHibernateFlushMode(this.sessionHolder.getPreviousFlushMode());
108107
}
109108
// Eagerly disconnect the Session here, to make release mode "on_close" work nicely.
110109
session.disconnect();

spring-orm/src/main/java/org/springframework/orm/hibernate5/support/OpenSessionInViewFilter.java

+1-2
Original file line numberDiff line numberDiff line change
@@ -204,11 +204,10 @@ protected SessionFactory lookupSessionFactory() {
204204
* @throws DataAccessResourceFailureException if the Session could not be created
205205
* @see FlushMode#MANUAL
206206
*/
207-
@SuppressWarnings("deprecation")
208207
protected Session openSession(SessionFactory sessionFactory) throws DataAccessResourceFailureException {
209208
try {
210209
Session session = sessionFactory.openSession();
211-
session.setFlushMode(FlushMode.MANUAL);
210+
session.setHibernateFlushMode(FlushMode.MANUAL);
212211
return session;
213212
}
214213
catch (HibernateException ex) {

spring-orm/src/main/java/org/springframework/orm/hibernate5/support/OpenSessionInViewInterceptor.java

+2-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2018 the original author or authors.
2+
* Copyright 2002-2020 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -186,11 +186,10 @@ public void afterConcurrentHandlingStarted(WebRequest request) {
186186
* @throws DataAccessResourceFailureException if the Session could not be created
187187
* @see FlushMode#MANUAL
188188
*/
189-
@SuppressWarnings("deprecation")
190189
protected Session openSession() throws DataAccessResourceFailureException {
191190
try {
192191
Session session = obtainSessionFactory().openSession();
193-
session.setFlushMode(FlushMode.MANUAL);
192+
session.setHibernateFlushMode(FlushMode.MANUAL);
194193
return session;
195194
}
196195
catch (HibernateException ex) {

spring-orm/src/main/java/org/springframework/orm/hibernate5/support/OpenSessionInterceptor.java

+1-2
Original file line numberDiff line numberDiff line change
@@ -111,13 +111,12 @@ public Object invoke(MethodInvocation invocation) throws Throwable {
111111
* @since 5.0
112112
* @see FlushMode#MANUAL
113113
*/
114-
@SuppressWarnings("deprecation")
115114
protected Session openSession(SessionFactory sessionFactory) throws DataAccessResourceFailureException {
116115
Session session = openSession();
117116
if (session == null) {
118117
try {
119118
session = sessionFactory.openSession();
120-
session.setFlushMode(FlushMode.MANUAL);
119+
session.setHibernateFlushMode(FlushMode.MANUAL);
121120
}
122121
catch (HibernateException ex) {
123122
throw new DataAccessResourceFailureException("Could not open Hibernate Session", ex);

0 commit comments

Comments
 (0)