在Spring Transaction JUnit测试中自动assemblyHibernate会话的正确方法

这个问题类似于前一个问题 。 我试图在我的一个Spring-JUnit-Transactional测试中@Autowire一个Hibernate Session但是我得到了这个exception:

java.lang.IllegalStateException: No Hibernate Session bound to thread, and configuration does not allow creation of non-transactional ...

这是我的JUnit类:

 @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations={"/applicationContext.xml"}) @TransactionConfiguration(transactionManager="transactionManager") @Transactional public class MyTest { @Qualifier("session") @Autowired private Session session; @Test public void testSomething() { session.get(User.class, "me@here.com"); } } 

如果我@Autowire一个SessionFactory并以编程方式获取我的Session (而不是在Spring XML中定义它),那么每个都可以正常工作:

 @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations={"/applicationContext.xml"}) @TransactionConfiguration(transactionManager="transactionManager") @Transactional public class MyTest{ @Qualifier("sessionFactory") @Autowired private SessionFactory sessionFactory; @Test public void testSomething() { Session session = SessionFactoryUtils.getSession(sessionFactory, false); session.get(User.class, "me@here.com"); } } 

但是,如果我使用在我的Spring XML中定义我的Session ,那么我可以得到我的原始示例:

    ...    classpath:/hibernate.cfg.xml  org.hibernate.cfg.AnnotationConfiguration               

我的问题是:为什么需要在我的unit testing中只有一个线程有限的事务上下文? 定义Hibernate Session bean的正确方法什么?

SessionFactoryUtils.getSession()与获取Session的任何其他方式一样好。 HibernateDaoSupport.getSession()会做同样的事情。

你需要scoped-proxy的原因是因为时间问题。 如果没有scoped-proxy,它似乎是在测试开始之前注入Session,因此在事务开始之前注入会话,因此你会得到错误。

通过添加scoped-proxy,它代理Session并注入它,因此它不会预先注入实际会话(在事务开始之前),而是仅在测试运行时获取并调用它,当它实际需要创建一个时打电话给它。

我认为“正确”的方式是注入SessionFactory ,并以编程方式从中获取Session。 您获得exception的原因归结为SessionFactoryUtils.getSession()的记录行为:

获取给定SessionFactory的Hibernate会话。 知道并将返回绑定到当前线程的任何现有对应Session,例如在使用HibernateTransactionManager时。 否则,如果“allowCreate”为true,则会创建一个新的Session。

由于没有任何内容将会话绑定到当前事务,因此失败。

我的建议是使用HibernateTemplate – 在你的上下文中定义一个,并将其自动装入你的测试中。 HibernateTemplate与war会话具有大部分相同的操作,但会为您处理会话处理。 你应该能够做到:

 hibernateTemplate.get(User.class, "me@here.com");