我有一个PostgreSQL 8.4数据库,其中包含一些表和视图,这些表和视图本质上是一些表上的连接.我使用NetBeans 7.2(如here所述)创建从这些视图和表派生的基于REST的服务,并将其部署到Glassfish 3.1.2.2服务器上.

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

我try 过向AbstractFacade类NetBeans生成中添加几个方法:

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

...

}

然后我从NetBeans生成的find个方法中调用doRefresh()个.通常情况下,IllegalArgumentsException被抛出,表示类似Can not refresh not managed object: EntityTypeImpl@28524907:MyView [ javaType: class org.my.rest.MyView descriptor: RelationalDescriptor(org.my.rest.MyView --> [DatabaseTable(my_view)]), mappings: 12].的内容

因此,我正在寻找一些关于如何正确刷新与视图关联的实体的建议,以便它是最新的.

更新:结果表明我对潜在问题的理解不正确.它在某种程度上与another question I posted earlier有关,即视图没有可以用作唯一标识符的单个字段.NetBeans要求我 Select 一个ID字段,所以我只 Select 了一个应该是多部分密钥的部分.这表明,具有特定ID字段的所有记录都是相同的,尽管数据库中有具有相同ID字段的记录,但其余部分不同.JPA只是查看了我告诉它的唯一标识符,然后简单地提取了它找到的第一条记录.

我通过添加一个唯一标识符字段解决了这个问题(从未能够让多部分密钥正常工作).

推荐答案

我建议添加一个@Startup @Singleton类,它可以建立到PostgreSQL数据库的JDBC连接,并使用LISTEN and NOTIFY来处理缓存失效.

Update: Here's another interesting approach, using pgq and a collection of workers for invalidation.

失效信号

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

现在,你的助手类对触发器发送的NOTIFY个事件执行LISTENs操作.当它得到一个NOTIFY事件时,它可以使单个缓存条目无效(见下文),或刷新整个缓存.你可以用PgJDBC's listen/notify support个键监听来自数据库的通知.您需要打开pooler managed java.sql.Connection中的任何连接,才能访问底层的PostgreSQL实现,这样就可以将其转换为org.postgresql.PGConnection并调用getNotifications().

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

缓存级别

EclipseLink/JPA有几个级别的缓存.

第一级缓存为EntityManager级缓存.如果一个实体通过persist(...)merge(...)find(...)等连接到EntityManager,那么当在同一会话中再次访问该实体时,无论您的应用程序是否仍有对其的引用,EntityManager都需要返回the same instance of that entity.如果数据库内容已更改,则此附加实例将不会是最新的.

二级缓存是可选的,为EntityManagerFactory级,是一种更传统的缓存.目前尚不清楚是否启用了二级缓存.判断你的日食记录和你的persistence.xml.您可以通过EntityManagerFactory.getCache()访问二级缓存;见Cache.

@Dayofcondor演示了如何使用以下内容刷新二级缓存:

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

但您也可以通过evict(java.lang.Class cls, java.lang.Object primaryKey)调用逐出单个对象:

em.getEntityManagerFactory().getCache().evict(theClass, thePrimaryKey);

您可以从@Startup @Singleton NOTIFY侦听器中使用它来仅使那些已更改的条目无效.

一级缓存并不容易,因为它是应用程序逻辑的一部分.你会想了解这EntityManager个附加和分离的实体是如何工作的.一个选项是始终对相关表使用分离的实体,在这里,每次获取实体时都使用新的EntityManager.这个问题:

Invalidating JPA EntityManager session

对如何处理实体管理器缓存的失效进行了有益的讨论.然而,EntityManager缓存不太可能是您的问题,因为RESTful web服务通常使用短的EntityManager个会话来实现.只有在使用扩展持久性上下文,或者创建和管理自己的EntityManager个会话而不是使用容器管理的持久性时,这才可能成为一个问题.

Postgresql相关问答推荐

优化PostgreSQL查询以将用户插入数据库

如何在postquist中修剪第一/后文件名

计算两个子查询之间的差异

Postgresql我必须创建一个索引还是已经有一个索引了?

Postgres:如何优化在多个表上搜索列的相似性查询?(Pg_Trgm)

Select 所有数组类型和维度

Postgres数据库系统已准备好接受连接和docker compose

PostgreSQL SELECT 结果具有不同的 id,它更喜欢来自另一个表的特定值

Heroku Rails 4 无法连接到服务器:connection refused

PostgreSQL:please specify covering index name是什么意思

使用 ON CONFLICT 从 INSERT 返回行,无需更新

如何更改几何列的 SRID?

是否可以在 Postgres 中存储一个 1 字节的数字?

在这个 Dockerfile 中创建的 Postgres 用户名/密码在哪里?

在 PostgreSQL 数组中查找值的位置

如何在带有 PostgreSQL 数据库的 Web 应用程序中拥有完整的离线功能?

获取全文搜索配置语言的完整列表

为什么 rake db:migrate 有时会在 structure.sql 中添加尾随空格?

实时监控 PostgreSQL 查询的应用程序?

如何更改 PostgreSQL 中的 REFERENCES?