提问者:小点点

如何在长时间运行的Seam对话中避免一级缓存


在长时间运行的对话中,我遇到了一个一级缓存问题(使用JPA/Hibernate和Seam 2.2)。

我们有一个使用长时间对话的搜索页面(一些ajax交互、模态编辑等需要)。

问题是,当另一个用户更改实体时,当用户再次单击搜索按钮时,更改不会显示。在这里看到类似的问题

因此,在长时间运行的会话中,实体从一级缓存加载,除非手动对每个实体调用刷新,否则不会加载其他事务中所做的更改。

我尝试使用CacheMode. IGNORE或CacheMode.REFRESH(通过Hibernate查询),但这并不能解决问题,因为它只处理二级缓存。

我可以看到select查询被发送到数据库,但Hibernate似乎仍在使用一级缓存中的缓存对象。

在进行新搜索之前,我曾尝试从以前的搜索中逐出实体,并且有效,但是后来我遇到了有线问题,因为会话中仍有指向现在被驱逐的实体的对象。你必须添加

@org.hibernate.annotations.Cascade({org.hibernate.annotations.CascadeType.EVICT,org.hibernate.annotations.CascadeType.REFRESH})

但是很容易忽略一个。

您也可以清除漏洞会话,但这可能会导致LazyOrialization错误。

有没有办法告诉 JPA/Hibernate 不要在查询上使用第一级缓存?

编辑:有一个很好的答案,为什么它不起作用,但刷新每个实体的建议并不理想。我以前使用过这个,但问题是,例如,对于200个条目的列表,你会向数据库生成200个单独的加载,这会使它非常慢。在这200个条目中,只有一两个可能发生了变化!那么,如何识别哪些实体发生了变化呢!我想,如果您在每次更改都会更新的实体上使用时间戳,那么您可以使用它。只需记录上一次搜索的时间戳,然后在列表中搜索自那以后更改的实体。你觉得有什么更优雅的解决方案吗?


共1个答案

匿名用户

解决此问题的方法可能是在EVENT范围内定义一个单独的持久性上下文工厂,并将其用于查询。在组件. xml中:

<persistence:managed-persistence-context scope="event" auto-create="true" 
    entity-manager-factory="#{yourfactory}" name="eventScopedEM" />

这样做的目的是在每个页面事件上创建一个新的实体管理器,而不是在整个对话中保持同一个实体管理器。保留另一个会话范围的持久性上下文工厂(默认为< code>#{entityManager})以供所有其他用途。如果使用< code>EntityQuery组件进行查询,请记住设置实体管理器的名称(否则默认为< code>entityManager),重写< code > getPersistenceContextName()方法(对于基于Java的查询组件)或显式设置实体管理器(对于基于xml的查询组件),例如:

<framework:entity-query entityManager="#{eventScopedEM}">
    <framework:ejbql>from MyEntity</framework:ejbql>
    ...
</framework:entity-query>