Browse Source

Derive StatelessSession from transactional Session on Hibernate 7.2

Closes gh-35664
See gh-7184
pull/35665/head
Juergen Hoeller 2 months ago
parent
commit
228662ad9f
  1. 41
      spring-orm/src/main/java/org/springframework/orm/jpa/hibernate/SpringSessionContext.java

41
spring-orm/src/main/java/org/springframework/orm/jpa/hibernate/SpringSessionContext.java

@ -42,6 +42,7 @@ import org.jspecify.annotations.Nullable; @@ -42,6 +42,7 @@ import org.jspecify.annotations.Nullable;
import org.springframework.jdbc.datasource.DataSourceUtils;
import org.springframework.orm.jpa.EntityManagerHolder;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import org.springframework.util.ClassUtils;
/**
* Implementation of Hibernate's {@link CurrentSessionContext} interface
@ -57,6 +58,9 @@ import org.springframework.transaction.support.TransactionSynchronizationManager @@ -57,6 +58,9 @@ import org.springframework.transaction.support.TransactionSynchronizationManager
@SuppressWarnings("serial")
public class SpringSessionContext implements CurrentSessionContext {
private static final boolean DERIVE_STATELESS_FROM_SESSION =
ClassUtils.hasMethod(Session.class, "statelessWithOptions"); // Hibernate 7.2+
private final SessionFactoryImplementor sessionFactory;
private @Nullable TransactionManager transactionManager;
@ -89,13 +93,14 @@ public class SpringSessionContext implements CurrentSessionContext { @@ -89,13 +93,14 @@ public class SpringSessionContext implements CurrentSessionContext {
*/
@Override
public Session currentSession() throws HibernateException {
// Determine pre-bound Session
Object value = TransactionSynchronizationManager.getResource(this.sessionFactory);
SessionHolder holder = null;
if (value instanceof Session session) {
return session;
}
else if (value instanceof SessionHolder sessionHolder) {
// HibernateTransactionManager
// from HibernateTransactionManager
if (sessionHolder.hasSession()) {
Session session = sessionHolder.getSession();
if (!sessionHolder.isSynchronizedWithTransaction() &&
@ -117,11 +122,12 @@ public class SpringSessionContext implements CurrentSessionContext { @@ -117,11 +122,12 @@ public class SpringSessionContext implements CurrentSessionContext {
holder = sessionHolder;
}
else if (value instanceof EntityManagerHolder entityManagerHolder) {
// JpaTransactionManager
// from JpaTransactionManager
return entityManagerHolder.getEntityManager().unwrap(Session.class);
}
if (this.transactionManager != null && this.jtaSessionContext != null) {
// Full JTA setup -> delegate to SpringJtaSessionContext
try {
if (this.transactionManager.getStatus() == Status.STATUS_ACTIVE) {
Session session = this.jtaSessionContext.currentSession();
@ -138,6 +144,7 @@ public class SpringSessionContext implements CurrentSessionContext { @@ -138,6 +144,7 @@ public class SpringSessionContext implements CurrentSessionContext {
}
if (TransactionSynchronizationManager.isSynchronizationActive()) {
// Lazily create Session
Session session;
DataSource dataSource = determineDataSource(this.sessionFactory);
if (dataSource != null) {
@ -148,9 +155,13 @@ public class SpringSessionContext implements CurrentSessionContext { @@ -148,9 +155,13 @@ public class SpringSessionContext implements CurrentSessionContext {
else {
session = this.sessionFactory.openSession();
}
// Apply read-only semantics
if (TransactionSynchronizationManager.isCurrentTransactionReadOnly()) {
session.setHibernateFlushMode(FlushMode.MANUAL);
}
// Bind transactional Session
if (holder != null) {
holder.setSession(session);
}
@ -159,9 +170,8 @@ public class SpringSessionContext implements CurrentSessionContext { @@ -159,9 +170,8 @@ public class SpringSessionContext implements CurrentSessionContext {
}
return session;
}
else {
throw new HibernateException("Could not obtain transaction-synchronized Session for current thread");
}
throw new HibernateException("Could not obtain transaction-synchronized Session for current thread");
}
@ -171,11 +181,12 @@ public class SpringSessionContext implements CurrentSessionContext { @@ -171,11 +181,12 @@ public class SpringSessionContext implements CurrentSessionContext {
* @return the current StatelessSession
*/
public static StatelessSession currentStatelessSession(SessionFactory sessionFactory) {
// Determine pre-bound StatelessSession
Object value = TransactionSynchronizationManager.getResource(sessionFactory);
SessionHolder holder = null;
if (value instanceof StatelessSession statelessSession) {
return statelessSession;
}
SessionHolder holder = null;
if (value instanceof SessionHolder sessionHolder) {
if (sessionHolder.hasStatelessSession()) {
return sessionHolder.getStatelessSession();
@ -184,7 +195,18 @@ public class SpringSessionContext implements CurrentSessionContext { @@ -184,7 +195,18 @@ public class SpringSessionContext implements CurrentSessionContext {
}
if (TransactionSynchronizationManager.isSynchronizationActive()) {
StatelessSession session = sessionFactory.openStatelessSession(determineConnection(sessionFactory, holder));
// Lazily create StatelessSession
StatelessSession session;
if (holder != null && DERIVE_STATELESS_FROM_SESSION) {
// from HibernateTransactionManager on Hibernate 7.2+
session = holder.getSession().statelessWithOptions().connection().open();
}
else {
// from JdbcTransactionManager (or HibernateTransactionManager against Hibernate 7.0/7.1)
session = sessionFactory.openStatelessSession(determineConnection(sessionFactory, holder));
}
// Bind transactional StatelessSession
if (holder != null) {
holder.setStatelessSession(session);
}
@ -193,9 +215,8 @@ public class SpringSessionContext implements CurrentSessionContext { @@ -193,9 +215,8 @@ public class SpringSessionContext implements CurrentSessionContext {
}
return session;
}
else {
throw new HibernateException("Could not obtain transaction-synchronized Session for current thread");
}
throw new HibernateException("Could not obtain transaction-synchronized Session for current thread");
}
private static void bindSessionHolder(SessionFactory sessionFactory, SessionHolder holder) {

Loading…
Cancel
Save