mirror of
https://github.com/spring-projects/spring-framework.git
synced 2026-09-17 08:24:13 +00:00
Derive StatelessSession from primary Session in HibernateJpaDialect
This is analogous to LocalSessionFactoryBean's SpringSessionContext. See gh-36025
This commit is contained in:
@@ -18,6 +18,7 @@ package org.springframework.orm.jpa;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Map;
|
||||
|
||||
import jakarta.persistence.EntityManager;
|
||||
import jakarta.persistence.PersistenceException;
|
||||
@@ -113,6 +114,27 @@ public class DefaultJpaDialect implements JpaDialect, Serializable {
|
||||
throws PersistenceException, SQLException {
|
||||
}
|
||||
|
||||
/**
|
||||
* Derive a new {@code EntityAgent} from the given {@code EntityManager} if possible,
|
||||
* sharing the transactional context.
|
||||
* <p><b>NOTE: This method is designed for Spring's early JPA 4.0 support.</b>
|
||||
* For JPA 3.2 compatibility, the return type cannot be enforced as
|
||||
* {@code jakarta.persistence.EntityAgent}. Subclasses should override it with
|
||||
* their specific EntityAgent type if possible, or otherwise just EntityAgent,
|
||||
* as a covariant return type. This will make it forward-compatible with a
|
||||
* future variant of this method in the {@link JpaDialect} interface itself.
|
||||
* @param entityManager the current JPA EntityManager
|
||||
* @param properties the properties for the EntityAgent, if any
|
||||
* @return the new EntityAgent instance, or {@code null} if none can be derived
|
||||
* @throws jakarta.persistence.PersistenceException if thrown by JPA methods
|
||||
* @since 7.0.4
|
||||
*/
|
||||
public @Nullable Object deriveEntityAgent(EntityManager entityManager, @Nullable Map<?, ?> properties)
|
||||
throws PersistenceException {
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------------
|
||||
// Hook for exception translation (used by JpaTransactionManager)
|
||||
|
||||
@@ -334,7 +334,15 @@ public abstract class EntityManagerFactoryUtils {
|
||||
|
||||
// Create a new EntityManager for use within the current transaction.
|
||||
logger.debug("Opening JPA EntityAgent");
|
||||
Object entityAgent = createEntityAgent(emf, properties);
|
||||
Object entityAgent = null;
|
||||
if (emHolder != null && emf instanceof EntityManagerFactoryInfo info &&
|
||||
info.getJpaDialect() instanceof DefaultJpaDialect defaultJpaDialect) {
|
||||
// For JpaTransactionManager: share transaction context with primary EntityManager.
|
||||
entityAgent = defaultJpaDialect.deriveEntityAgent(emHolder.getEntityManager(), properties);
|
||||
}
|
||||
if (entityAgent == null) {
|
||||
entityAgent = createEntityAgent(emf, properties);
|
||||
}
|
||||
|
||||
if (emHolder != null) {
|
||||
emHolder.setEntityAgent(entityAgent);
|
||||
|
||||
+25
-1
@@ -16,8 +16,10 @@
|
||||
|
||||
package org.springframework.orm.jpa.vendor;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Map;
|
||||
|
||||
import jakarta.persistence.EntityManager;
|
||||
import jakarta.persistence.PersistenceException;
|
||||
@@ -25,6 +27,7 @@ import org.hibernate.ConnectionReleaseMode;
|
||||
import org.hibernate.FlushMode;
|
||||
import org.hibernate.JDBCException;
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.StatelessSession;
|
||||
import org.hibernate.engine.spi.SessionImplementor;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
@@ -39,10 +42,12 @@ 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.ClassUtils;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
/**
|
||||
* {@link org.springframework.orm.jpa.JpaDialect} implementation for Hibernate.
|
||||
* Compatible with Hibernate ORM 7.x.
|
||||
* Compatible with Hibernate ORM 7.x and 8.x.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @author Costin Leau
|
||||
@@ -54,6 +59,10 @@ import org.springframework.transaction.support.ResourceTransactionDefinition;
|
||||
@SuppressWarnings("serial")
|
||||
public class HibernateJpaDialect extends DefaultJpaDialect {
|
||||
|
||||
/** Hibernate 8.0: inherited setProperty(String, Object) method from JPA 4.0 EntityAgent. */
|
||||
private static final @Nullable Method STATELESS_SESSION_SET_PROPERTY = ClassUtils.getMethodIfAvailable(
|
||||
StatelessSession.class, "setProperty", String.class, Object.class);
|
||||
|
||||
private final HibernateExceptionTranslator exceptionTranslator = new HibernateExceptionTranslator();
|
||||
|
||||
boolean prepareConnection = true;
|
||||
@@ -194,6 +203,21 @@ public class HibernateJpaDialect extends DefaultJpaDialect {
|
||||
return new HibernateConnectionHandle(entityManager.unwrap(SessionImplementor.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
public StatelessSession deriveEntityAgent(EntityManager entityManager, @Nullable Map<?, ?> properties)
|
||||
throws PersistenceException {
|
||||
|
||||
StatelessSession entityAgent = entityManager.unwrap(Session.class).statelessWithOptions().connection().open();
|
||||
if (properties != null && STATELESS_SESSION_SET_PROPERTY != null) {
|
||||
for (Map.Entry<?, ?> entry : properties.entrySet()) {
|
||||
if (entry.getKey() instanceof String key) {
|
||||
ReflectionUtils.invokeMethod(STATELESS_SESSION_SET_PROPERTY, entityAgent, key, entry.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
return entityAgent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable DataAccessException translateExceptionIfPossible(RuntimeException ex) {
|
||||
return this.exceptionTranslator.translateExceptionIfPossible(ex);
|
||||
|
||||
+1
-1
@@ -50,7 +50,7 @@ import org.springframework.transaction.jta.JtaTransactionManager;
|
||||
|
||||
/**
|
||||
* {@link org.springframework.orm.jpa.JpaVendorAdapter} implementation for Hibernate.
|
||||
* Compatible with Hibernate ORM 7.x.
|
||||
* Compatible with Hibernate ORM 7.x and 8.x.
|
||||
*
|
||||
* <p>Exposes Hibernate's persistence provider and Hibernate's Session as extended
|
||||
* EntityManager interface, and adapts {@link AbstractJpaVendorAdapter}'s common
|
||||
|
||||
Reference in New Issue
Block a user