hibernate jpa:会话已关闭!

时间:2011-02-28 18:02:49

标签: java hibernate spring jpa transactions

应用程序基于Spring 2.5.5和hibernate 3.2.0 GA。

我的DAO中有以下方法,它将MessageEntities附加到指定的用户:

public MessageEntity findByUserId(int userId) {
      List<MessageEntity> result = (List<MessageEntity>) em.createNamedQuery(MessageEntity.Q_BY_USER_ID).setParameter("userId", userId).getResultList();
      if (!result.isEmpty()) {
         return result.get(0);
      } else {
         return null;
     }
}

我需要从集成测试中调用此方法来检查系统的行为是否有效。只要这个方法不是事务性的,我得到的就是 org.hibernate.SessionException:Session被关闭了!。避免这种情况的最简单方法是使用 @Transactional(readOnly = true)标记 findByUserId 方法。但据我了解,事务管理应该是服务层的职责,以避免不必要的事务创建。所以,我的问题是:我怎样才能正确地摆脱 SessionException

3 个答案:

答案 0 :(得分:6)

需要在事务范围内执行所有数据库操作。当您确定通常被认为是好的设计时,让数据库模型的服务层处理事务。然后,唯一的约束就是必须调用服务模型才能进入事务范围,这在测试期间可能是不受欢迎的。

我建议使用spring提供的测试 fascilites。见9.3.2.3 Transaction management

您还可以在测试方法之前手动创建交易,例如通过

Session sess = factory.openSession();
Transaction tx = null;
// try catch 
tx = sess.beginTransaction();
findByUserId(userId);
tx.commit();
tx.rollBack();

答案 1 :(得分:1)

将以下注释放在测试类的顶部。

@RunWith(SpringJUnit4ClassRunner.class)
@Transactional
@ContextConfiguration(locations = "classpath:/META-INF/spring/applicationContext.xml")

另外,我不担心在DAO中添加额外的@Transactional。 Spring通常会在创建另一个事务之前检查您是否已经在事务中(在同一个线程中)。

  

“但据我了解,交易   管理应该是的责任   服务层以避免不必要的   交易创造。“

This is more of a design choice(例如Spring Roo违反此规定)

答案 2 :(得分:0)

您可以在控制器方法上使用此注释:

@Transactional(readOnly = true)