4

请原谅我这个问题,但到目前为止我无法通过我的研究找到任何解决方案。(至少没有什么对我有帮助)

我的情况:

  • 我正在将休眠用于 vaadin 网络服务
  • 网络服务正在获取上传的文档,并通过休眠将它们放在我的 MySQL 数据库中
  • 后台的计算服务(稍后可能在另一台服务器上的单独进程)对上传的文档执行计算任务,并将结果再次添加到数据库中
  • 网络服务识别数据库中的分析结果并将其显示给用户

我的问题:

  • 我的问题是 1 级休眠缓存
  • 计算服务启动后,他不会对后来更新的文档进行任何计算,因为当他完成给定的搜索查询时,它们不会出现在他的缓存中。
  • 我的网络服务覆盖在计算服务器中进行了更改,因为它也不知道任何关于它的信息。

我知道休眠 1 级缓存是造成这种行为的原因(顺便说一下,2 级缓存不活动)。

到目前为止我尝试过的

  • 我读了很多书并尝试了几件事,例如在各个地方调用 session.clear() 。这经常给我“会话已关闭”异常并且没有帮助我(尽管我读到有人提到这有助于解决他们的问题)

  • 我试图确保会话最终总是关闭,但这并没有解决问题,而且我读到我不需要手动关闭会话,在我使用 transaction.commit() 之后(我听说这是每个请求模式的会话标准)

  • 每次我的计算服务需要搜索数据库时,我都尝试关闭我的 sessionfactory 并重新打开它。如果我也在我的 Web 服务上执行此操作,这部分工作并且可能全部工作,但这对我来说似乎不是一个很好的解决方案(也消耗内存,不是吗?)

  • 我尝试添加

<property name="hibernate.connection.isolation">2</property>

到我的 hibernate.cfg.xml,但这也只是部分起作用。使用这个我的计算服务执行计算任务,但每次通过 Web 服务上传新数据时,他的更改都会再次被覆盖。因此检测到了新的上传,但是一旦有新的上传到达,所有已经分析过的文档都会再次被分析。

我一直在思考我管理会话的方式是否不正确。我的 DAO 类有两个方法,在事务的每次开始和结束时都会调用它们。

public abstract class DAO {

/**
 * Returns the current hibernate session. Also takes care that there's
 * always an open hibernate transaction when needed.
 * 
 * @return Current hibernate session
 */
public static Session getSession() {
    Session currentSession = HibernateUtil.getSessionFactory()
            .getCurrentSession();
    if (!currentSession.getTransaction().isActive()) {
        currentSession.beginTransaction();
    }

    return currentSession;
}

/**
 * Closes the current hibernate session, if there is one.
 */
public static void closeSession() {
    Session sess = HibernateUtil.getSessionFactory().getCurrentSession();
    if (sess.getTransaction().isActive()) {
        sess.getTransaction().commit();
    }
    ThreadLocalSessionContext.unbind(HibernateUtil.getSessionFactory());
}

}

我也读过一些关于 Optimistic Locking with hibernate 的内容,但我不确定这是否能解决我的问题。我读到乐观锁定只会在缓存对象不是数据库中的对象时抛出异常。但是它是否也加载(刷新)缓存呢?

你是如何在你的休眠中处理这个问题的?你有什么建议我可以做什么,或者我什至在我的 DAO 课程中做错了什么?我对代码示例也很满意。再说一遍:我希望每个进程都知道另一个进程在数据库中所做的更改。(如果可以的话,我什至会禁用第一个缓存,但因为这是不可能的)

非常感谢您的每一个回答,并认为您正在与我分享

4

2 回答 2

5

附加对象实例仅存Session在于 Hibernate 中。如果您正确终止事务和会话,一级缓存将被清除。您使用什么模式进行会话管理?会话中?

我问这个,因为你的问题在我看来就像一个会话终止问题。

编辑:

我在您的代码中没有看到 Session.close() 或至少 Session.disconnect() 。据我所知,unbind() 不是自动的。

于 2012-07-02T23:16:54.140 回答
1

我已经解决了我的问题。

在 Gergely Szilagyi 和他的回答的大力帮助下,第一部分可以得到解决:

附加对象实例仅存在于 Hibernate 的 Session 中。如果您正确终止事务和会话,一级缓存将被清除。您使用什么模式进行会话管理?会话中?

我问这个,因为你的问题在我看来就像一个会话终止问题。

编辑:

我在您的代码中没有看到 Session.close() 或至少 Session.disconnect() 。据我所知,unbind() 不是自动的。

(感谢这篇精彩的帖子,如果我可以将几个答案标记为正确,我也会标记你的!)

他的回答让我想到了我的会话管理,我的一些问题通过这个得到了解决。

我的问题的第二部分,在我的主要问题中也非常重要的是如何刷新一级缓存/使其保持一致。经过大量研究,我发现hibernate Session 类包含一个可以直接从数据库加载对象的方法。

给定要刷新的 Entity 对象实体,您可以执行以下操作:

//Call session.evict if this object is currently in the session, otherwise not necessary
//It deletes the object from the session cache (If you don't call this method although this object is currenlty in the session an exception will be thrown
session.evict(entity);
//session.get acccesses the database directly and returns you the actual saved entity
Ent1 updatedEntitEnty = (Ent1) session.get(Ent1.class, entity.getPrimaryUniqueID());

现在您可以继续使用收到的更新实体。

session.get(...) 是这里最重要的方法,因为它直接访问数据库并忽略缓存。给定的返回对象是保存在数据库中的最新对象。

注意:还有一个 session.load(...) 方法,在这种情况下没有帮助。load(..) 访问缓存并从那里检索对象,而 get(..) 则正确。

因此,如果您想从数据库中检索对象,请不要使用 session.load(...)!

我希望这个答案在某一天对其他人有所帮助,如果您有任何问题,请与我联系。

于 2012-07-04T13:12:01.710 回答