0

我有一个已标记的服务@Transactional。唯一的问题是,我正在研究在调用 save 方法时需要提交对象的方法。

我已经从类级别中删除了注释,并将除我的之外的每个方法都标记为@Transactional(DAO 也被标记@Transactional)。我确实看到我的信息现在正在像我想要的那样立即保存,但是当我尝试执行 findBy 时,我得到了“线程中不存在会话”异常。

有谁知道这个问题以及如何解决它?

4

1 回答 1

2

所以我将不得不对你的方法在做什么做一些有根据的猜测,因为你没有向我们提供你的服务类和 DAO 正在做什么的任何细节。

首先,@Transactional最好的做法是标记您的服务方法,因为您的服务类应该管理您的事务会话。您的 DAO 应该仅用于访问数据库并以表单形式返回您的对象,以便您可以使用它们。会话不是 DAO 应该担心的事情。

现在我猜你的服务类看起来像这样:

@Transactional
public void saveOrUpdateFoo(Foo foo){
    fooDao.saveOrUpdate(foo);
}

@Transactional
public Foo manipulateFoo(Foo foo){
    //Do stuff to your Foo object that you want to be changed.
    saveOrUpdateFoo(foo);
    //Database hasn't actually changed yet.
    foo = fooDao.findBy(foo.getFooId());
    //nothing will change here.
}

要了解为什么您的数据库在您调用 时实际上并没有改变saveOrUpdateFoo(foo),您需要了解@Transactional注解实际上导致 Hibernate 所做的事情。当您@Transactional在告诉 Hibernate 时标记方法时,该方法中的所有内容都需要在单个数据库会话中发生,并且如果出现问题应该回滚。

为了促进这一点,当您调用currentSession().save(foo);DAO(我假设您正在这样做)时,Hibernate 会获取您的对象,并在内存中更新该对象的本地“克隆”。(这实际上不是它的工作原理,只是想象一下 Hibernate 在事务启动时根据数据库保留它自己的对象副本,当您调用 save/update 时,它​​会更改这些副本)

当您的@Transactional方法退出时,Hibernate 会将这些更改刷新到数据库,这是您的数据库状态实际更改的时候。saveOrUpdateFoo如果这个对象是一个新对象(因为在数据库中必须创建一个新记录),Hibernate 应该在您调用时使用保存数据库时将使用的值更新它管理的任何 ID 字段。保存对象后,您不需要“重新获取”对象,它应该处于一种状态,就好像您实际上已将INSERT其放入数据库,然后SELECT再次将其保存,而实际上并未将更改持久保存到数据库。

这不应该是一个问题,除非您尝试在另一个线程中从数据库中获取对象,而这一切都在进行,在这种情况下,您需要重新设计您的服务类,以免发生这种情况。

如果这不能解决您的问题,请发布您的服务类和 DAO,以及您实际尝试做什么的说明。

于 2015-03-24T05:16:52.543 回答