Roger that
Roger that

Reputation: 474

Load entities without locking rows in database

Is there an option in JPA to load an entity (or a list of) without locking the database? I would like to be able to do it in just a few methods. Also is it possible for JPA to load the entity without locking the database, BUT when anything change on that entity, just then it lock the row in the database? Validating the state of course, if the entity is already changed in the database throws an exception of invalid state.

Upvotes: 0

Views: 1217

Answers (1)

wypieprz
wypieprz

Reputation: 8219

Is there an option in JPA to load an entity (or a list of) without locking the database?

Entities can be loaded by means of different EntityManager's calls:

  • EntityManager.find
  • EntityManager.createQuery
  • EntityManager.createNamedQuery
  • EntityManager.createNativeQuery

You don't need to use LockModeType.None explicitly in these calls. This is the default option in JPA represented by LockModeType.None.

Also is it possible for JPA to load the entity without locking the database, BUT when anything change on that entity, just then it lock the row in the database?

Entities can be locked by means of different calls:

  • EntityManager.find
  • EntityManager.lock
  • EntityManager.refresh
  • Query.setLockMode

I would say it is possible but not guaranteed by JPA as it depends on the persistence provider (vendor-specific) and type of locking being used.

Anyway such scenario may have look like this:

// begin tx
...
SomeEntity e = em.find(SomeEntity.class, id);
// change the entity
em.lock(e, LockModeType.OPTIMISTIC); // LockModeType.OPTIMISTIC_FORCE_INCREMENT
...
// commit tx

Now, it depends on a persistence provider whether locking will be eager (when lock is called) or deferred (when tx completes). Keep in mind that another transaction may lock the entity as the first one and you will end up with rollback.

From JPA Specification 2.0, chapter 3.4.4.1 OPTIMISTIC, OPTIMISTIC_FORCE_INCREMENT:

If transaction T1 calls lock(entity, LockModeType.OPTIMISTIC) on a versioned object, the entity manager must ensure that neither of the following phenomena can occur:

  • P1 (Dirty read): Transaction T1 modifies a row. Another transaction T2 then reads that row and obtains the modified value, before T1 has committed or rolled back. Transaction T2 eventually commits successfully; it does not matter whether T1 commits or rolls back and whether it does so before or after T2 commits.
  • P2 (Non-repeatable read): Transaction T1 reads a row. Another transaction T2 then modifies or deletes that row, before T1 has committed. Both transactions eventually commit successfully.

This will generally be achieved by the entity manager acquiring a lock on the underlying database row. While with optimistic concurrency, long-term database read locks are typically not obtained immediately, a compliant implementation is permitted to obtain an immediate lock (so long as it is retained until commit completes). If the lock is deferred until commit time, it must be retained until the commit completes. Any implementation that supports repeatable reads in a way that prevents the above phenomena is permissible

If transaction T1 calls lock(entity,LockModeType.OPTIMISTIC_FORCE_INCREMENT) on a versioned object, the entity manager must avoid the phenomena P1 and P2 (as with LockModeType.OPTIMISTIC) and must also force an update (increment) to the entity's version column. A forced version update may be performed immediately, or may be deferred until a flush or commit.

Upvotes: 1

Related Questions