首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用多个会话的JPA实体与数据库不同步

使用多个会话的JPA实体与数据库不同步
EN

Stack Overflow用户
提问于 2016-10-13 03:44:31
回答 1查看 1.3K关注 0票数 1

我有一个使用Eclipselink实现的带有JPA的Java EE应用程序。我已经使用ExternalContext会话映射实现了一个基本用户登录系统。然而,似乎经常会出现会话与数据库不同步的情况。

基本流程是1.用户A创建一个BidOrder实体。2.用户B创建AskOrder实体。3.监视器检查两个订单是否匹配,如果匹配,则创建一个OrderBook实体4.将更改推送到所有用户(使用Primefaces 5.3推送)

当我检查价格时,我在我的主视图的SessionScoped支持bean中使用了这个方法:

代码语言:javascript
复制
public void findLatestPrices()
 {
    logger.log(Level.INFO, "findLatestPrices with user {0} ",user.getUserId());

    findAllOrderBooks(); 
    latestPricesId = new ArrayList<String>();
    setLatestPricesResults(request.findLatestPrices());
     for (Iterator<OrderBook> it = orderBookResults.iterator(); it.hasNext();) 
     {
        OrderBook orderBook = it.next(); 
        logger.log(Level.INFO, "Found {0} orderbook price", orderBook.getPrice());
     }

     logger.log(Level.INFO, "End of findLatestPrices with user {0} ",user.getUserId());
 }

这就是我的RequestScoped有状态ejb:

代码语言:javascript
复制
public List<OrderBook> findLatestPrices() {
        List<OrderBook> orderBooks;
        List<OrderBook> orderBooksFiltered;

        Map<Member, OrderBook> map = new LinkedHashMap<Member, OrderBook>();

         try {
             orderBooks = em.createNamedQuery(
                     "findAllOrderBooks").setHint("javax.persistence.cache.storeMode", "REFRESH")
                     .getResultList();
             for (Iterator<OrderBook> it = orderBooks.iterator(); it.hasNext();) {
                 OrderBook orderBook = it.next();
                 Member member = orderBook.getBidOrderId().getMember();
                 map.put(member, orderBook);

                    logger.log(Level.INFO, "findLatestPrices orderbook price : {0}", 
                            orderBook.getPrice());
                    logger.log(Level.INFO, "findLatestPrices orderbook bidorder member : {0}", 
                            orderBook.getBidOrderId().getMember().getMemberId());
                    logger.log(Level.INFO, "findLatestPrices orderbook lastupdate : {0}", 
                            orderBook.getLastUpdate());
             }
...}

我用下面的方法在上面的bean中创建了EntityManager:

代码语言:javascript
复制
@PersistenceContext
private EntityManager em;

从日志记录中,我可以看到会话返回的数据与数据库不同步,例如,当我希望返回两个结果时返回单个结果,等等。正如你所看到的,我已经尝试了setHint来刷新缓存。我还在我的OrderBook实体和@Cache(refreshAlways=true)上尝试了@Cacheable(false),但都没有用。

我在创建的实体(OrderBook)的@PostPersist中发送一个推送事件。然后,我的xhtml页面中的javascript事件处理程序调用以下远程命令:

代码语言:javascript
复制
<p:remoteCommand name="updateWidget"
             autoRun="false"
             actionListener="#{parliamentManager.findLatestPrices}"
             update="resultDisplay"
             onstart="onStart()"
             oncomplete="onComplete()"
             onsuccess="onSuccess()"
             onerror="onError()">
             <f:actionListener binding="#{parliamentManager.findTraders()}"  />
             <f:actionListener binding="#  {parliamentManager.findPortfolios()}" />
             </p:remoteCommand>

似乎findLatestPrices的结果通常不包括所有会话的最新OrderBook实体。有没有可能实体在调用@PostPersist时没有立即持久化,而是在JPA完全持久化和反映实体之前将推送发送到一些会话?

为了演示,我添加了一个简单的命令按钮来手动调用updateWidget()。如果会话没有更新,而我单击了该按钮,它将始终更新为最新数据。

谢谢,佐博

EN

回答 1

Stack Overflow用户

发布于 2016-10-13 11:58:27

会话之间没有锁定,所以我不太确定你的意思。在大多数JPA提供程序文档中,建议使用乐观锁定来防止覆盖陈旧的数据。

您还没有展示或指定如何获取EntityManager,或者它的生存期有多长,但是有两个级别的缓存。第一个是EntityManager本身,它用于跟踪更改以管理实体并维护其身份。JPA允许但不强制要求在EntityManagerFactory级别共享的第二级缓存。这第二级缓存是javax.persistence.cache.storeMode的目标-它控制从共享缓存中拉出实体时发生的事情。如果实体已经加载到一级缓存中,因为这意味着表示事务作用域,它们将按原样返回,保留应用程序可能已经做出的任何非同步更改,并且需要JPA提供程序进行跟踪。

JPA强制刷新托管实体的唯一方法是调用em.refresh(),不过也可以通过调用em.clear,然后使用javax.persistence.cache.storeMode刷新提示重新读取实体来实现。EclipseLink还有一个"eclipselink.refresh“查询提示,可用于强制查询刷新托管实体实例。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/40007066

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档