如何通过外部更新保持您的hibernate 1级缓存一致?

时间:2012-07-02 23:10:47

标签: java mysql hibernate caching orm

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

我的情况:

  • 我正在使用hibernate进行vaadin webservice
  • Web服务正在上传文档,并通过我的MySQL数据库中的hibernate将它们保持不变
  • 后台的计算服务(以后可能在另一台服务器上的单独进程)对上载的文档执行计算任务,并在数据库中再次添加结果
  • Web服务识别数据库中的分析结果并将其显示给用户

我的问题:

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

我知道hibernate 1级缓存负责此行为(顺便说一下lvl 2缓存不活动)。

到目前为止我尝试了什么

  • 我已经阅读了很多内容并尝试了几种方法,例如在各个地方调用session.clear()。这经常给我“会话已关闭”的例外并没有帮助我(虽然我读到人们提到这有助于他们的问题)

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

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

  • 我尝试添加

  

< 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());
}

}

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

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

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

2 个答案:

答案 0 :(得分:5)

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

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

编辑:

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

答案 1 :(得分:1)

我已经解决了我的问题。

第一部分可以在Gergely Szilagyi及其答案的帮助下得到解决:

  

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

     

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

     

编辑:

     

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

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

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

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

给定要刷新的实体对象,您将采取以下措施:

//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(...)!

我希望有一天这个答案可以帮助别人,如果您有任何疑问,请与我联系。