对物化视图的多线程访问:同时刷新和读取似乎导致不一致的行为

Multithreaded access to the materialized views: refresh and read at the same time seems to result in inconsistent behaviour

我有一个类似this one的问题,但不幸的是,那里没有给出答案,所以我将在这里描述我的情况。

我有一个多线程 Java 网络应用程序,我通过 Spring JDBC 访问 PostgreSQL 数据库。

在一个线程中,我可能会像这样刷新数据库中的物化视图(基于某些事件):

jdbcTemplate.execute(Queries.REFRESH_MATERIALIZED_VIEWS);

其中 Queries.REFRESH_MATERIALIZED_VIEWS 定义为:

    String REFRESH_MATERIALIZED_VIEWS = "" +
            "REFRESH MATERIALIZED VIEW blablabla1;" +
            "REFRESH MATERIALIZED VIEW blablabla2;" +
            "";

在另一个线程中,我可能还会从同时更新的视图中读取数据。请注意,我没有在 REFRESH 语句中使用 CONCURRENTLY SQL 关键字,因此根据 [=17],我希望视图被读取锁定(AccessExclusiveLock) =](因为我想始终从中获取 "fresh" 数据)。

但似乎这种锁定并没有发生(或者我做错了什么),因为第二个线程有时 returns 是一个空集合。有时它 returns 是一个完全更新的集合。

这里似乎存在一些同步问题,因为结果取决于时间。

所以问题是:我如何确保访问这些视图的第二个线程将始终获取更新的数据而不是空集合?是否有一些Spring数据内置机制来确保一致性?

关于交易的更新(根据评论)。

刷新是在单个事务中完成的,但不是读取,由于应用程序的多线程性质,这显然是不可能的:读取线程可能由调度程序生成,它对其他线程及其事务一无所知, 正在同时刷新视图。

显然,它确实与交易有关,但方式有所不同。所以我在一个用 @TransactionalEventListener(classes = DataReloadEvent.class) 注释的方法中使用了我的视图刷新代码,因为我只需要在另一个事务提交后触发刷新。但是这个方法没有它自己的 @Transactional 注释。添加后,问题消失了,现在一切似乎都同步了。对我来说看起来有点黑魔法,但它确实有效,所以我会保持这种状态。