3

I am saving objects using Spring Data JPA save(Object entity) method from a multi-threaded web application.

Occasionally I find that when I load an object from the session using:

findOne(long id)

The object returned from the session is stale and doesn't reflect the latest version from the database. I am ONLY saving data from this application and ONLY using one instance of Spring Data JPA interface.

What could be causing it and how should I fix this?

Vlad Mihalcea
  • 142,745
  • 71
  • 566
  • 911
DD.
  • 21,498
  • 52
  • 157
  • 246
  • I've checked the cache and it is using @Cache(usage = CacheConcurrencyStrategy.READ_WRITE) – DD. Sep 23 '14 at 13:20

1 Answers1

3

Hibernate uses the PreparedStatement#executeUpdate result to check the number of updated rows. If no row was matched, it then throws a StaleObjectStateException (when using Hibernate API) or an OptimisticLockException (when using JPA).

Optimistic locking is a generic-purpose concurrency control technique, and it works for both physical and application-level transactions.

So the stale exceptions prevent the "lost update" phenomena when multiple concurrent requests modify the same shared persistent data.

In an application-level transaction, once you load an entity you will get a logical repeatable read due to 1st level cache (Persistence Context), but other users can still modify the aforementioned entity.

So you can indeed run into stale entities, but the optimistic locking mechanism prevents loosing updates without taking any additional database locks, and it even works for long conversations.

Vlad Mihalcea
  • 142,745
  • 71
  • 566
  • 911
  • What do you by other users? I only have the one application. – DD. Sep 30 '14 at 13:06
  • Even single applications might be accessed by multiple concurrent requests. – Vlad Mihalcea Sep 30 '14 at 13:12
  • Yes but all requests are being processed by a singleton EntityManager. The EntityManager should not have any stale data. – DD. Oct 06 '14 at 14:18
  • The entity manager is thread bound. That's why we use the PersistenceContext and not Resource or Inject. The entity manager is not a singleton. It gets created on a transaction boundary. – Vlad Mihalcea Oct 06 '14 at 15:20