Merge branch '7.0.x'

# Conflicts:
#	framework-platform/framework-platform.gradle
This commit is contained in:
Juergen Hoeller
2026-09-14 16:22:05 +02:00
6 changed files with 102 additions and 14 deletions
@@ -54,6 +54,13 @@ public class EntityManagerHolder extends ResourceHolderSupport {
this.entityAgent = entityAgent;
}
protected EntityManagerHolder(EntityManagerHolder original) {
this.entityManager = original.entityManager;
this.entityAgent = original.entityAgent;
this.transactionActive = original.transactionActive;
this.savepointManager = original.savepointManager;
}
void setEntityManager(EntityManager entityManager) {
this.entityManager = entityManager;
@@ -44,6 +44,7 @@ import org.springframework.jdbc.datasource.DataSourceUtils;
import org.springframework.jdbc.datasource.JdbcTransactionObjectSupport;
import org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy;
import org.springframework.orm.jpa.EntityManagerFactoryUtils;
import org.springframework.orm.jpa.EntityManagerHolder;
import org.springframework.transaction.CannotCreateTransactionException;
import org.springframework.transaction.IllegalTransactionStateException;
import org.springframework.transaction.InvalidIsolationLevelException;
@@ -391,9 +392,17 @@ public class HibernateTransactionManager extends AbstractPlatformTransactionMana
txObject.setSavepointAllowed(isNestedTransactionAllowed());
SessionFactory sessionFactory = obtainSessionFactory();
SessionHolder sessionHolder =
(SessionHolder) TransactionSynchronizationManager.getResource(sessionFactory);
if (sessionHolder != null) {
Object resource = TransactionSynchronizationManager.getResource(sessionFactory);
if (resource instanceof EntityManagerHolder emHolder) {
SessionHolder sessionHolder;
if (emHolder instanceof SessionHolder originalSessionHolder) {
sessionHolder = originalSessionHolder;
}
else {
sessionHolder = new SessionHolder(emHolder);
TransactionSynchronizationManager.unbindResource(sessionFactory);
TransactionSynchronizationManager.bindResource(sessionFactory, sessionHolder);
}
if (logger.isDebugEnabled()) {
logger.debug("Found thread-bound Session [" + sessionHolder.getSession() + "] for Hibernate transaction");
}
@@ -16,6 +16,7 @@
package org.springframework.orm.jpa.hibernate;
import jakarta.persistence.EntityManager;
import org.hibernate.FlushMode;
import org.hibernate.Session;
import org.hibernate.StatelessSession;
@@ -49,10 +50,14 @@ public class SessionHolder extends EntityManagerHolder {
}
SessionHolder(StatelessSession session) {
super(null);
super((EntityManager) null);
setStatelessSession(session);
}
SessionHolder(EntityManagerHolder emHolder) {
super(emHolder);
}
void setSession(Session session) {
this.entityManager = session;
@@ -187,7 +187,16 @@ public class SpringSessionContext implements CurrentSessionContext {
if (value instanceof StatelessSession statelessSession) {
return statelessSession;
}
if (value instanceof SessionHolder sessionHolder) {
else if (value instanceof EntityManagerHolder emHolder) {
SessionHolder sessionHolder;
if (emHolder instanceof SessionHolder originalSessionHolder) {
sessionHolder = originalSessionHolder;
}
else {
sessionHolder = new SessionHolder(emHolder);
TransactionSynchronizationManager.unbindResource(sessionFactory);
TransactionSynchronizationManager.bindResource(sessionFactory, sessionHolder);
}
if (sessionHolder.hasStatelessSession()) {
return sessionHolder.getStatelessSession();
}
@@ -216,7 +225,7 @@ public class SpringSessionContext implements CurrentSessionContext {
return session;
}
throw new HibernateException("Could not obtain transaction-synchronized Session for current thread");
throw new HibernateException("Could not obtain transaction-synchronized StatelessSession for current thread");
}
private static void bindSessionHolder(SessionFactory sessionFactory, SessionHolder holder) {
@@ -32,7 +32,10 @@ import org.springframework.context.ApplicationContext;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.orm.jpa.AbstractContainerEntityManagerFactoryIntegrationTests;
import org.springframework.orm.jpa.EntityManagerFactoryInfo;
import org.springframework.orm.jpa.EntityManagerHolder;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.domain.Person;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import org.springframework.transaction.support.TransactionTemplate;
import static org.assertj.core.api.Assertions.assertThat;
@@ -150,6 +153,61 @@ class HibernateNativeEntityManagerFactoryIntegrationTests extends AbstractContai
});
}
@Test
void withJpaTransactionManager() {
String firstName = "Tony";
insertPerson(firstName);
Query<Person> q = statelessSession.createQuery("select p from Person as p", Person.class);
assertThat(q.getResultList()).hasSize(1);
assertThat(q.getResultList().get(0).getFirstName()).isEqualTo(firstName);
endTransaction();
JpaTransactionManager dstm = new JpaTransactionManager(sessionFactory);
new TransactionTemplate(dstm).execute(status -> {
insertPerson(firstName);
Query<Person> q2 = statelessSession.createQuery("select p from Person as p", Person.class);
assertThat(q2.getResultList()).hasSize(1);
assertThat(q2.getResultList().get(0).getFirstName()).isEqualTo(firstName);
Query<Person> q3 = sharedSession.createQuery("select p from Person as p", Person.class);
assertThat(q3.getResultList()).hasSize(1);
assertThat(q3.getResultList().get(0).getFirstName()).isEqualTo(firstName);
status.setRollbackOnly();
return null;
});
}
@Test
void withPreBoundEntityManager() {
String firstName = "Tony";
insertPerson(firstName);
Query<Person> q = statelessSession.createQuery("select p from Person as p", Person.class);
assertThat(q.getResultList()).hasSize(1);
assertThat(q.getResultList().get(0).getFirstName()).isEqualTo(firstName);
endTransaction();
Session session = sessionFactory.openSession();
TransactionSynchronizationManager.bindResource(sessionFactory, new EntityManagerHolder(session));
startNewTransaction();
insertPerson(firstName);
Query<Person> q2 = statelessSession.createQuery("select p from Person as p", Person.class);
assertThat(q2.getResultList()).hasSize(1);
assertThat(q2.getResultList().get(0).getFirstName()).isEqualTo(firstName);
Query<Person> q3 = sharedSession.createQuery("select p from Person as p", Person.class);
assertThat(q3.getResultList()).hasSize(1);
assertThat(q3.getResultList().get(0).getFirstName()).isEqualTo(firstName);
endTransaction();
session.close();
TransactionSynchronizationManager.unbindResource(sessionFactory);
}
@Test // SPR-16956
void readOnly() {
assertThat(sessionFactory.getCurrentSession().getHibernateFlushMode()).isSameAs(FlushMode.AUTO);