Reliably track changes made by Hibernate

I am using PostUpdateEventListener registered through

 registry.appendListeners(EventType.POST_COMMIT_UPDATE, listener) 

and a few other listeners to track changes made by Hibernate. This works great, however, I see a problem there:

Say to track some amount on id I just do

  amountByIdConcurrentMap.put(id, amount); 

on each POST_COMMIT_UPDATE (let other operations be ignored). The problem is that this call happens some time after the commit. Thus, with two commits that write the same object immediately one after another, I can receive events in the wrong order, eventually saving the old amount .

  • Is this really possible or are the operations synchronized in some way?
  • Is there any way to prevent or at least detect such a situation?
+5
source share
2 answers

Two questions and a suggestion later

  • Are you sure you need this optimization. Why not get the amount as it is written in the database by requesting there. Which gives you reason to work with caching.

  • How do you make sure that the calculation of the amount before it is written to the database is correctly synchronized, so that several threads or, possibly, the nodes do not use the old data to calculate the amount and, therefore, overwrite the result with a later calculation?

I suppose you are dealing with question number 2 correctly. Then you have options:

  • Pessimistic locking, this means that just before committing, you can exclusively update your cache without concurrency problems.
  • Optimistic lock: in this case, you have some kind of timestamp or counter in your database record, which you can also cache in the amount. This is a value that you can use to find out what the last value represents.
+2
source

No, there are no guarantees of the order, so you will need to take care to ensure the correct synchronization manually.

If the real problem that you are solving is caching the state of the object, and if it is suitable for using the second level cache for the entity in question, you will get everything out of the box by enabling the L2 cache.

Otherwise, instead of directly updating the map from update listeners, you can send tasks to the RU-NIC or messaging system, which asynchronously starts a new transaction and select for update amount for this identifier from the database. Then update the card in the same transaction, holding the corresponding row lock in db, so that card updates for the same identifier are performed in series.

+2
source

Source: https://habr.com/ru/post/1273304/


All Articles