LocalSessionFactoryBean and HibernateTransactionManager for JPA setup

SessionHolder extends EntityManagerHolder now, allowing for @PersistenceContext and co to interact with HibernateTransactionManager's thread-bound transactions, and SpringSessionContext is capable of interacting with JpaTransactionManager by detecting a plain EntityManagerHolder as well.

Issue: SPR-17002
This commit is contained in:
Juergen Hoeller
2018-07-04 15:07:09 +02:00
parent a5dd0f0c09
commit 094c9b8bd2
16 changed files with 226 additions and 70 deletions

View File

@@ -45,6 +45,7 @@ import org.springframework.beans.factory.InitializingBean;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.lang.Nullable;
import org.springframework.transaction.support.ResourceHolderSupport;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import org.springframework.util.Assert;
import org.springframework.util.ReflectionUtils;
@@ -1117,8 +1118,8 @@ public class HibernateTemplate implements HibernateOperations, InitializingBean
criteria.setMaxResults(getMaxResults());
}
SessionHolder sessionHolder =
(SessionHolder) TransactionSynchronizationManager.getResource(obtainSessionFactory());
ResourceHolderSupport sessionHolder =
(ResourceHolderSupport) TransactionSynchronizationManager.getResource(obtainSessionFactory());
if (sessionHolder != null && sessionHolder.hasTimeout()) {
criteria.setTimeout(sessionHolder.getTimeToLiveInSeconds());
}
@@ -1146,8 +1147,8 @@ public class HibernateTemplate implements HibernateOperations, InitializingBean
queryObject.setMaxResults(getMaxResults());
}
SessionHolder sessionHolder =
(SessionHolder) TransactionSynchronizationManager.getResource(obtainSessionFactory());
ResourceHolderSupport sessionHolder =
(ResourceHolderSupport) TransactionSynchronizationManager.getResource(obtainSessionFactory());
if (sessionHolder != null && sessionHolder.hasTimeout()) {
queryObject.setTimeout(sessionHolder.getTimeToLiveInSeconds());
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2017 the original author or authors.
* Copyright 2002-2018 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.
@@ -16,18 +16,20 @@
package org.springframework.orm.hibernate5;
import javax.persistence.EntityManager;
import org.hibernate.FlushMode;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.springframework.lang.Nullable;
import org.springframework.transaction.support.ResourceHolderSupport;
import org.springframework.util.Assert;
import org.springframework.orm.jpa.EntityManagerHolder;
/**
* Session holder, wrapping a Hibernate Session and a Hibernate Transaction.
* HibernateTransactionManager binds instances of this class to the thread,
* for a given SessionFactory.
* Resource holder wrapping a Hibernate {@link Session} (plus an optional {@link Transaction}).
* {@link HibernateTransactionManager} binds instances of this class to the thread,
* for a given {@link org.hibernate.SessionFactory}. Extends {@link EntityManagerHolder}
* as of 5.1, automatically exposing an {@code EntityManager} handle on Hibernate 5.2+.
*
* <p>Note: This is an SPI class, not intended to be used by applications.
*
@@ -36,7 +38,7 @@ import org.springframework.util.Assert;
* @see HibernateTransactionManager
* @see SessionFactoryUtils
*/
public class SessionHolder extends ResourceHolderSupport {
public class SessionHolder extends EntityManagerHolder {
private final Session session;
@@ -48,7 +50,7 @@ public class SessionHolder extends ResourceHolderSupport {
public SessionHolder(Session session) {
Assert.notNull(session, "Session must not be null");
super(EntityManager.class.isInstance(session) ? session : null);
this.session = session;
}
@@ -59,6 +61,7 @@ public class SessionHolder extends ResourceHolderSupport {
public void setTransaction(@Nullable Transaction transaction) {
this.transaction = transaction;
setTransactionActive(transaction != null);
}
@Nullable

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 the original author or authors.
* Copyright 2002-2018 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.
@@ -29,12 +29,13 @@ import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.transaction.jta.platform.spi.JtaPlatform;
import org.springframework.lang.Nullable;
import org.springframework.orm.jpa.EntityManagerHolder;
import org.springframework.transaction.support.TransactionSynchronizationManager;
/**
* Implementation of Hibernate 3.1's CurrentSessionContext interface
* that delegates to Spring's SessionFactoryUtils for providing a
* Spring-managed current Session.
* Implementation of Hibernate 3.1's {@link CurrentSessionContext} interface
* that delegates to Spring's {@link SessionFactoryUtils} for providing a
* Spring-managed current {@link Session}.
*
* <p>This CurrentSessionContext implementation can also be specified in custom
* SessionFactory setup through the "hibernate.current_session_context_class"
@@ -86,6 +87,7 @@ public class SpringSessionContext implements CurrentSessionContext {
return (Session) value;
}
else if (value instanceof SessionHolder) {
// HibernateTransactionManager
SessionHolder sessionHolder = (SessionHolder) value;
Session session = sessionHolder.getSession();
if (!sessionHolder.isSynchronizedWithTransaction() &&
@@ -104,13 +106,18 @@ public class SpringSessionContext implements CurrentSessionContext {
}
return session;
}
else if (value instanceof EntityManagerHolder) {
// JpaTransactionManager
return ((EntityManagerHolder) value).getEntityManager().unwrap(Session.class);
}
if (this.transactionManager != null && this.jtaSessionContext != null) {
try {
if (this.transactionManager.getStatus() == Status.STATUS_ACTIVE) {
Session session = this.jtaSessionContext.currentSession();
if (TransactionSynchronizationManager.isSynchronizationActive()) {
TransactionSynchronizationManager.registerSynchronization(new SpringFlushSynchronization(session));
TransactionSynchronizationManager.registerSynchronization(
new SpringFlushSynchronization(session));
}
return session;
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2017 the original author or authors.
* Copyright 2002-2018 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.
@@ -24,9 +24,12 @@ import org.springframework.transaction.support.ResourceHolderSupport;
import org.springframework.util.Assert;
/**
* Holder wrapping a JPA EntityManager.
* JpaTransactionManager binds instances of this class to the thread,
* for a given EntityManagerFactory.
* Resource holder wrapping a JPA {@link EntityManager}.
* {@link JpaTransactionManager} binds instances of this class to the thread,
* for a given {@link javax.persistence.EntityManagerFactory}.
*
* <p>Also serves as a base class for {@link org.springframework.orm.hibernate5.SessionHolder},
* as of 5.1.
*
* <p>Note: This is an SPI class, not intended to be used by applications.
*
@@ -37,6 +40,7 @@ import org.springframework.util.Assert;
*/
public class EntityManagerHolder extends ResourceHolderSupport {
@Nullable
private final EntityManager entityManager;
private boolean transactionActive;
@@ -45,13 +49,13 @@ public class EntityManagerHolder extends ResourceHolderSupport {
private SavepointManager savepointManager;
public EntityManagerHolder(EntityManager entityManager) {
Assert.notNull(entityManager, "EntityManager must not be null");
public EntityManagerHolder(@Nullable EntityManager entityManager) {
this.entityManager = entityManager;
}
public EntityManager getEntityManager() {
Assert.state(this.entityManager != null, "No EntityManager available");
return this.entityManager;
}