0

I have a question similar to this one, but, unfortunately, the answer was not given there, so I'll describe my situation here.

I have a multithreaded Java web app where I access the PostgreSQL database via Spring JDBC.

In one thread I may refresh materialized views in the database like this (based on some events):

jdbcTemplate.execute(Queries.REFRESH_MATERIALIZED_VIEWS);

Where Queries.REFRESH_MATERIALIZED_VIEWS is defined as:

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

In another thread, I may also read data from the views being updated at the same time. Note that I don't use CONCURRENTLY SQL keyword in the REFRESH statement, so I expect the view to be read-locked (AccessExclusiveLock), according to this question and that answer (because I want to always get the "fresh" data out of it).

But it seems that this locking is just not happening (or maybe I'm doing something wrong) because this second thread sometimes returns an empty collection. And sometimes it returns a fully updated collection.

It looks like there's some synchronization issue here because the results are dependent on timing.

So the question is: how can I make sure that the second thread, that is accessing those views, will always fetch the updated data and not an empty collection? Is there some Spring Data built-in mechanism to ensure consistency?

Update regarding transactions (based on the comment).

Refreshes are done in a single transaction, but not reads, which is obviously not possible due to the multithreaded nature of the app: read-threads may be spawned by a scheduler, which knows nothing about other threads and their transactions, which are refreshing the view at the same time.

Dmytro Titov
  • 2,802
  • 6
  • 38
  • 60
  • You should do all refreshs in a single transaction –  Jul 25 '19 at 13:03
  • Refreshes are done in a single transaction, but not reads, which is obviously not possible due to the multithreaded nature of the app. – Dmytro Titov Jul 25 '19 at 13:05

1 Answers1

0

Apparently, it was really about transactions, but in a somewhat different way. So I had my views refresh code in a method annotated with @TransactionalEventListener(classes = DataReloadEvent.class) because I needed to trigger refresh only after another transaction's commit. But this method didn't have it's own @Transactional annotation. After I added it, the issue was gone and now everything seems to be synchronized. Looks like a bit of black magic to me, but it works, so I'll keep it like that.

Dmytro Titov
  • 2,802
  • 6
  • 38
  • 60