当前位置: 首页 > 知识库问答 >
问题:

如何在后端数据库异步更改时刷新JPA实体?

钱志强
2023-03-14

我有一个PostgreSQL 8.4数据库,其中有一些表和视图,它们实际上是一些表上的联接。我使用NetBeans7.2(如本文所述)创建基于REST的服务,这些服务派生自这些视图和表,并将它们部署到Glassfish 3.1.2.2服务器上。

还有另一个进程,它异步更新用于构建视图的某些表中的内容。我可以直接查询视图和表,并看到这些更改已经正确发生。但是,当从基于REST的服务中提取时,这些值与数据库中的值不同。我假设这是因为JPA在Glassfish服务器上缓存了数据库内容的本地副本,并且JPA需要刷新相关的实体。

我尝试向NetBeans生成的AbstractFacade类添加两个方法:

public abstract class AbstractFacade<T> {
    private Class<T> entityClass;
    private String entityName;
    private static boolean _refresh = true;

    public static void refresh() { _refresh = true; }

    public AbstractFacade(Class<T> entityClass) {
        this.entityClass = entityClass;
        this.entityName = entityClass.getSimpleName();
    }

    private void doRefresh() {
        if (_refresh) {
            EntityManager em = getEntityManager();
            em.flush();

            for (EntityType<?> entity : em.getMetamodel().getEntities()) {
                if (entity.getName().contains(entityName)) {
                    try {
                        em.refresh(entity);
                        // log success
                    }
                    catch (IllegalArgumentException e) {
                        // log failure ... typically complains entity is not managed
                    }
                }
            }

            _refresh = false;
        }
    }

...

}

共有1个答案

雍河
2023-03-14

我建议添加一个@startup@singleton类,用于建立到PostgreSQL数据库的JDBC连接,并使用listennotify来处理缓存无效。

更新:这里有另一个有趣的方法,使用pgq和一个工人集合进行无效化。

在正在更新的表上添加一个触发器,该触发器每当更新实体时都会发送notify。在PostgreSQL 9.0及以上版本中,notify可以包含有效负载,通常是行ID,因此不必使整个缓存无效,只需使已更改的实体无效即可。在不支持有效负载的旧版本中,您可以将无效条目添加到helper类在获得notify时查询的时间戳日志表中,或者只是使整个缓存无效。

作为侦听通知的替代方法,您可以在计时器上轮询更改日志表,并在问题表上设置触发器,将更改的行ID和更改时间戳追加到更改日志表。除了需要为每种DB类型设置不同的触发器之外,这种方法是可移植的,但它效率低且不及时。它将需要频繁的低效轮询,并且仍然具有监听/通知方法所没有的时间延迟。在PostgreSQL中,可以使用unlogged表来稍微降低这种方法的成本。

Eclipselink/JPA有两个级别的缓存。

第一级缓存位于EntityManager级。如果一个实体通过persist(...)merge(...)find(...)等附加到EntityManager,那么当在同一会话中再次访问该实体时,EntityManager必须返回该实体的同一实例,无论应用程序是否仍然引用该实体。如果数据库内容已经更改,则此附加实例将不是最新的。

第二级缓存是可选的,位于EntityManagerFactory级别,是一种更传统的缓存。不清楚您是否启用了二级缓存。检查您的EclipseLink日志和persistence.xml。您可以通过EntityManagerFactory.getcache()访问第二级缓存;请参见缓存

@TheDayOfCondor展示了如何用以下内容刷新二级缓存:

em.getEntityManagerFactory().getCache().evictAll();

但是也可以使用evict(java.lang.class cls,java.lang.Object primaryKey)调用逐出各个对象:

em.getEntityManagerFactory().getCache().evict(theClass, thePrimaryKey);
 类似资料:
  • 问题内容: 我有一个带有某些表和视图的PostgreSQL 8.4数据库,这些表和视图本质上是对某些表的联接。我使用的NetBeans 7.2(如描述这里)来从这些观点和表导出并部署那些到Glassfish的3.1.2.2服务器基于REST的服务。 还有另一个过程可以异步更新用于构建视图的某些表中的内容。我可以直接查询视图和表,并查看这些更改已正确发生。但是,从基于REST的服务中提取时,这些值与

  • 问题内容: 发生更改时,如何检测对数据库的最新更新并以静默方式刷新页面? 假设数据库访问如下所示: 任何想法和样品将不胜感激。谢谢。 问题答案: 这就是我最近使用jQuery实现解决方案的方式。 每当发生 重大 更新时,PHP都会在数据库中增加一个字段。 最初加载页面时,使用数据库中的数字填充JavaScript变量:

  • 我从这个问题中编辑了一个柱塞

  • 之前name的更新是同步更新的没有问题现在需要走接口,等接口返回后再更新,我试过在这个文件中调用dispath但是调用报错,请问下这种异步的数据该怎么更新

  • 未解决最初的关闭原因 让我们假设出现这种情况: 为什么? 有没有一种方法可以在Spring-Data中“同步”(开箱即用)对象(或者强制刷新)?还是我在要求奇迹?我不是讽刺,但也许我不是那么内行,也许(或者可能)是我的无知。如果是这样,请解释我为什么,并(如果你想)分享一些关于这个惊人的框架的先进知识。

  • 这个问题几乎说明了一切。使用JPARepository,我如何更新一个实体? JPARepository只有一个save方法,它并不告诉我它实际上是create还是update。例如,我向数据库用户插入一个简单的对象,它有三个字段:、和: 然后我只需调用,此时它实际上是对数据库的插入: 到目前为止还不错。现在我想更新这个用户,比如说改变他的年龄。为此,我可以使用查询,无论是QueryDSL还是Na