I suggest you do this (it seems hacked, but with outdated code, sometimes required)
This solution uses the Spring TransactionSynchronizationManager and Hibernate 4, but can be adapted to a different version of Hibernate.
Here is the idea: using the custom implementation of CurrentSessionContext in your SessionFactoryBean, and this custom implementation will look for the current transaction in the transaction resources for the entity manager; when it is found, it simply calls the code sent by IIla to receive the hibernation session.
For this:
1. Define the hibernate.current_session_context_class property in hibernateProperties:
<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean"> ... <property name="hibernateProperties"> <props> ... <prop key="hibernate.current_session_context_class"> com.example.jpa.HibernateSessionInEntityManager </prop> </props> </property> </bean> <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> <property name="jpaVendorAdapter"> <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"/> </property> <property name="dataSource" ref="dataSource"/> <property name="packagesToScan" value="com.example.jpa.validator"/> </bean> <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"> <property name="dataSource" ref="dataSource" /> <property name="entityManagerFactory" ref="entityManagerFactory" /> </bean>
2.Configure your custom CurrentSessionContext: HibernateSessionInEntityManager.java
import org.hibernate.HibernateException; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.context.spi.CurrentSessionContext; import org.hibernate.ejb.EntityManagerImpl; import org.hibernate.engine.spi.SessionFactoryImplementor; import org.springframework.orm.jpa.EntityManagerHolder; import org.springframework.transaction.support.TransactionSynchronizationManager; import javax.persistence.EntityManager; import java.util.Map; public class HibernateSessionInEntityManager implements CurrentSessionContext { public HibernateSessionInEntityManager() { } public HibernateSessionInEntityManager(SessionFactory sessionFactory) { } public HibernateSessionInEntityManager(SessionFactoryImplementor sessionFactory) { } public Session currentSession() throws HibernateException { Map<Object, Object> resourceMap = TransactionSynchronizationManager.getResourceMap(); for(Object v:resourceMap.values()){ if(v instanceof EntityManagerHolder){ return getSessionFromEM(((EntityManagerHolder)v).getEntityManager()); } } return null; } private static Session getSessionFromEM(final EntityManager entityManager) { final Object emDelegate = entityManager.getDelegate(); if (emDelegate instanceof EntityManagerImpl) { return ((EntityManagerImpl) emDelegate).getSession(); } else if (emDelegate instanceof Session) { return (Session) emDelegate; } throw new HibernateException("No Session found"); } }
Pay attention to all those constructors: Hibernate-4 needs one with SessionFactoryImplementor , and I think Hibernate-3 needs one with SessionFactory . (The no-args constructor is probably not required)
3. Here is a simple test case to verify that it works.
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations = { "classpath:ApplicationContext.xml" }) public class HibernateSessionInEntityManagerTest { @Autowired public SessionFactory sessionFactory; @Test @Transactional public void testGetHibernateSession(){ Session session = sessionFactory.getCurrentSession(); Assert.assertNotNull(session); } }
Hope this helps. (By the way: good question)
Important note: if you have several EntityManagerFactoryBean, you can choose a good one by studying transactional resources. (i.e., for example, look at the persistenceUnitName of the associated entityManagerFactory object)