我更改了我的应用程序以使用 Hibernate EntityManager(来自 Hibernate session ),
但我有一些在下面的代码中使用的旧代码(我无法更改这些代码):
getSessionFactory().getCurrentSession()
.
我有 sessionFactory 的 bean,所以上面的代码应该可以工作,但在运行时我有
HibernateException("No Session found for current thread")
,即使上面的代码是在事务 block 中执行的。
仅供引用:我检查了事务资源(在 Debug模式下),并且使用 EntityManagerFactory 键, session 存在,但不在 SessionFactory 键下
最佳答案
我建议你这样做(看起来很hacky,但对于遗留代码,有时是必需的)
此解决方案使用 Spring TransactionSynchronizationManager和Hibernate 4,但可以适配其他Hibernate版本。
想法如下:使用 CurrentSessionContext 的自定义实现在您的 SessionFactoryBean 中,此自定义实现将在事务资源中搜索当前事务的实体管理器;当发现时,只需调用 IIla 发布的代码即可获取 hibernate session 。
要做到这一点:
1.在hibernateProperties中定义属性hibernate.current_session_context_class
:
<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>
<!-- for completness : here are the other relevant beans -->
<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.实现自定义 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");
}
}
注意所有这些构造函数:Hibernate-4 需要带有 SessionFactoryImplementor
的构造函数,我认为 Hibernate-3 需要带有 SessionFactory
的构造函数。 (无参数构造函数可能不是必需的)
3.这里有一个简单的测试用例来验证它是否有效
@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);
}
}
希望对您有所帮助。 (顺便说一句:好问题)
重要提示:如果您有多个 EntityManagerFactoryBean,请在查看事务资源时小心选择好的一个。 (例如,查看关联的entityManagerFactory的persistenceUnitName)
关于java - Hibernate EntityManager 与 getSessionFactoryGetCurrentSession(),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18759978/