首页 > 解决方案 > 多线程访问物化视图:同时刷新和读取似乎会导致不一致的行为

问题描述

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

我有一个多线程 Java Web 应用程序,我通过 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;" +
            "";

在另一个线程中,我还可以从同时更新的视图中读取数据。请注意,我没有CONCURRENTLY在语句中使用 SQL 关键字,因此根据这个问题那个答案REFRESH,我希望视图被读锁定( ) (因为我希望始终从中获取“新鲜”数据)。AccessExclusiveLock

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

看起来这里有一些同步问题,因为结果取决于时间。

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

有关交易的更新(基于评论)。

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

标签: javamultithreadingpostgresqlspring-dataspring-jdbc

解决方案


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


推荐阅读