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.
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.
Related
This is just an insert to db at the end of a transaction. Is there any point in using entityManager.flush()?
#Transactional
public long saveNewWallet(String name) {
Wallet emptyWallet = new Wallet();
emptyWallet.setAmount(new BigDecimal(2.00));
entityManager.persist(emptyWallet);
entityManager.flush();
return 5;
}
Since you are in a #Transactional scope, the changes are sent to the database but are not actually committed until Spring's transaction interceptor commits the local transaction. In that scenario you could remove it.
The following entry explains the uses of EntityManager.flush(): https://en.wikibooks.org/wiki/Java_Persistence/Persisting
Flush
The EntityManager.flush() operation can be used to write all changes
to the database before the transaction is committed. By default JPA
does not normally write changes to the database until the transaction
is committed. This is normally desirable as it avoids database access,
resources and locks until required. It also allows database writes to
be ordered, and batched for optimal database access, and to maintain
integrity constraints and avoid deadlocks. This means that when you
call persist, merge, or remove the database DML INSERT, UPDATE, DELETE
is not executed, until commit, or until a flush is triggered.
The flush() does not execute the actual commit: the commit still
happens when an explicit commit() is requested in case of resource
local transactions, or when a container managed (JTA) transaction
completes.
Flush has several usages:
Flush changes before a query execution to enable the query to return new objects and changes made in the persistence unit.
Insert persisted objects to ensure their Ids are assigned and accessible to the application if using IDENTITY sequencing.
Write all changes to the database to allow error handling of any database errors (useful when using JTA or SessionBeans).
To flush and clear a batch for batch processing in a single transaction.
Avoid constraint errors, or reincarnate an object.
I am looking at EntityManager API, and I am trying to understand an order in which I would do a record lock. Basically when a user decides to Edit a record, my code is:
entityManager.getTransaction().begin();
r = entityManager.find(Route.class, r.getPrimaryKey());
r.setRoute(txtRoute.getText());
entityManager.persist(r);
entityManager.getTransaction().commit();
From my trial and error, it appears I need to set WWEntityManager.entityManager.lock(r, LockModeType.PESSIMISTIC_READ); after the .begin().
I naturally assumed that I would use WWEntityManager.entityManager.lock(r, LockModeType.NONE); after the commit, but it gave me this:
Exception Description: No transaction is currently active
I haven't tried putting it before the commit yet, but wouldn't that defeat the purpose of locking the record, since my goal is to avoid colliding records in case 50 users try to commit a change at once?
Any help as to how to I can lock the record for the duration of the edit, is greatly appreciated!
Thank You!
Performing locking inside transaction makes perfectly sense. Lock is automatically released in the end of the transaction (commit / rollback). Locking outside of transaction (in context of JPA) does not make sense, because releasing lock is tied to end of the transaction. Also otherwise locking after changes are performed and transaction is committed does not make too much sense.
It can be that you are using pessimistic locking to purpose other than what they are really for. If my assumption is wrong, then you can ignore end of the answer. When your transaction holds pessimistic read lock on entity (row), following is guaranteed:
No dirty reads: other transactions cannot see results of operations you performed to locked rows.
Repeatable reads: no modifications from other transactions
If your transaction modifies locked entity, PESSIMISTIC_READ is upgraded to PESSIMISTIC_WRITE or transaction fails if lock cannot be upgraded.
Following coarsely describes scenario with obtaining locking in the beginning of transaction:
entityManager.getTransaction().begin();
r = entityManager.find(Route.class, r.getPrimaryKey(),
LockModeType.PESSIMISTIC_READ);
//from this moment on we can safely read r again expect no changes
r.setRoute(txtRoute.getText());
entityManager.persist(r);
//When changes are flushed to database, provider must convert lock to
//PESSIMISTIC_WRITE, which can fail if concurrent update
entityManager.getTransaction().commit();
Often databases do not have separate support for pessimistic read, so you are actually holding lock to row since PESSIMISTIC_READ. Also using PESSIMISTIC_READ makes sense only if no changes to the locked row are expected. In case above changes are done always, so using PESSIMISTIC_WRITE from the beginning on is reasonable, because it saves you from the risk of concurrent update.
In many cases it also makes sense to use optimistic instead of pessimistic locking. Good examples and some comments about choosing between locking strategies can be found from: Locking and Concurrency in Java Persistence 2.0
Great work attempting to be safe in write locking your changing data. :) But you might be going overboard / doing it the long way.
First a minor point. The call to persist() isn't needed. For update, just modify the attributes of the entity returned from find(). The entityManager automatically knows about the changes and writes them to the db during commit. Persist is only needed when you create a new object & write it to the db for the first time (or add a new child object to a parent relation and which to cascade the persist via cascade=PERSIST).
Most applications have a low probability of 'clashing' concurrent updates to the same data by different threads which have their own separate transactions and separate persistent contexts. If this is true for you and you would like to maximise scalability, then use an optimistic write lock, rather than a pessimistic read or write lock. This is the case for the vast majority of web applications. It gives exactly the same data integrity, much better performance/scalability, but you must (infrequently) handle an OptimisticLockException.
optimistic write locking is built-in automatically by simply having a short/integer/long/TimeStamp attribute in the db and entity and annotating it in the entity with #Version, you do not need to call entityManager.lock() in that case
If you were satisfied with the above, and you added a #Version attribute to your entity, your code would be:
try {
entityManager.getTransaction().begin();
r = entityManager.find(Route.class, r.getPrimaryKey());
r.setRoute(txtRoute.getText());
entityManager.getTransaction().commit();
} catch (OptimisticLockException e) {
// Logging and (maybe) some error handling here.
// In your case you are lucky - you could simply rerun the whole method.
// Although often automatic recovery is difficult and possibly dangerous/undesirable
// in which case we need to report the error back to the user for manual recovery
}
i.e. no explicit locking at all - the entity manager handles it automagically.
IF you had a strong need to avoid concurrent data update "clashes", and are happy to have your code with limited scalability then serialise data access via pessimistic write locking:
try {
entityManager.getTransaction().begin();
r = entityManager.find(Route.class, r.getPrimaryKey(), LockModeType.PESSIMISTIC_WRITE);
r.setRoute(txtRoute.getText());
entityManager.getTransaction().commit();
} catch (PessimisticLockException e) {
// log & rethrow
}
In both cases, a successful commit or an exception with automatic rollback means that any locking carried out is automatically cleared.
Cheers.
I have a DBManager singleton that ensures instantiation of a single EntityManagerFactory. I'm debating on the use of single or multiple EntityManager though, because a only single transaction is associated with an EntityManager.
I need to use multiple transactions. JPA doesn't support nested transactions.
So my question is: In most of your normal applications that use transactions in a single db environment, do you use a single EntityManager at all? So far I have been using multiple EntityManagers but would like to see if creating a single one could do the trick and also speed up a bit.
So I found the below helpful: Hope it helps someone else too.
http://en.wikibooks.org/wiki/Java_Persistence/Transactions#Nested_Transactions
Technically in JPA the EntityManager is in a transaction from the
point it is created. So begin is somewhat redundant. Until begin is
called, certain operations such as persist, merge, remove cannot be
called. Queries can still be performed, and objects that were queried
can be changed, although this is somewhat unspecified what will happen
to these changes in the JPA spec, normally they will be committed,
however it is best to call begin before making any changes to your
objects. Normally it is best to create a new EntityManager for each
transaction to avoid have stale objects remaining in the persistence
context, and to allow previously managed objects to garbage collect.
After a successful commit the EntityManager can continue to be used,
and all of the managed objects remain managed. However it is normally
best to close or clear the EntityManager to allow garbage collection
and avoid stale data. If the commit fails, then the managed objects
are considered detached, and the EntityManager is cleared. This means
that commit failures cannot be caught and retried, if a failure
occurs, the entire transaction must be performed again. The previously
managed object may also be left in an inconsistent state, meaning some
of the objects locking version may have been incremented. Commit will
also fail if the transaction has been marked for rollback. This can
occur either explicitly by calling setRollbackOnly or is required to
be set if any query or find operation fails. This can be an issue, as
some queries may fail, but may not be desired to cause the entire
transaction to be rolled back.
The rollback operation will rollback the database transaction only.
The managed objects in the persistence context will become detached
and the EntityManager is cleared. This means any object previously
read, should no longer be used, and is no longer part of the
persistence context. The changes made to the objects will be left as
is, the object changes will not be reverted.
EntityManagers by definition are not thread safe. So unless your application is single threaded, using a single EM is probably not the way to go.
i read that upon session.flush()
The
data will be synchronized (but not committed) when session.flush() is called
what is synchronized with what..
whether it is DB state that will come to memory by querying or
memory state will be copied to Db ?
clarify this plz..
Calling session.flush() will cause SQL statements to be generated for all of the changes you have made, and those SQL statements to be executed on the database, within the sessios transaction scope.
Car car = (Car) session.get(Car.class, 1);
car.setModel("Mustang");
session.flush();
The last line will cause an UPDATE statement on the database. However, depending on how you handle transactions in your applications, this change might not be visible to other users before you commit the transaction held by the section.
While flushing is not really a bi-directional operation, it can be used to ensure that an auto generated identifier is assigned to a new entity object. If the Car class is mapped to a database table with an auto incrementing identifier, you can use flush to ensure that this identifier is available on the domain object in your application code:
Car car = new Car();
car.setModel("Torino");
session.save(car);
System.out.println(car.getId()); // prints 0
session.flush();
System.out.println(car.getId()); // prints something larger than 0
Say you want to send an email with a link to the newly created car (ok, a user account would have made more sense), but if the mail cannot be sent, you wish to rollback your transaction. Flushing the session allows you to do this.
"Flushing is the process of synchronizing the underlying persistent
store with persistable state held in memory."
By default the flush mode is set to AUTO and in this case session is flushed before query execution in order to ensure that queries never return stale state.
Flushing synchronizes the underlying persistent store with persistable state held in memory but not vice-versa. In other words, "in memory state is copied to the database" in the running transaction, to reuse your words. Note that flushing doesn't mean the data can't be rolled back.
I have an application using JPA, Hibernate and ehcache, as well as Spring's declarative
transactions. The load on DB is rather high so everything is cached to speed things up,
including collections. Now it is not a secret that collections are cached separately
from the entities that own them so if I delete an entity that is an element of such
cached collection, persist an entity that should be an element of one, or update an
entity such that it travels from one collection to another, I gotta perform the eviction
by hand.
So I use a hibernate event listener which keeps track of entities being inserted, deleted
or updated and saves that info for a transaction synchronization registered with Spring's
transaction manager to act upon. The synchronization then performs the eviction once the
transaction is committed.
Now the problem is that quite often, some other concurrent transaction manages to find
a collection in the cache that has just been evicted (these events are usually tenths of a
second apart according to log) and, naturally, causes an EntityNotFoundException to occur.
How do I synchronize this stuff correctly?
I tried doing the eviction in each of the 4 methods of TransactionSynchronization (which
are invoked at different points in time relative to transaction completion), it didn't help.
Essentially what you need to do is to force a read from the database in the event that a collection is in the process of or has just been evicted. One way to do this would be to mark the collection as dirty as soon as a request to evict it has been received but before entering the transaction to change it. Any concurrent transaction which comes along will check the dirty flag and if its set to true, it should get the data from the database otherwise it can read from the cache. You might need to change your DB transaction settings so that concurrent transactions block till the one updating the data finishes so that correct data is read from the DB. Once the transaction finishes, you can then reset the dirty flag to false.
You can also create a lock on the cached collection when an update, insert or delete is due for as long as the eviction lasts. This will ensure that no other transaction can read/change the cached collection till the eviction process finishes.
Why can't you must keep the collections up to date? i.e. when you add an object, add the object to the collection it belongs to. When you delete an object, remove it from the collection it is in. In my experience when using a cache with hibernate or jpa the state of the object (not the state of the database) is cached so you need to make sure your object model in memory is in sync with the object model on the database.
Or am I missing something? Why can't you simply keep the collections uptodate?
i think you must refer this link : -
Hibernate: Clean collection's 2nd level cache while cascade delete items
see, hibernate does not actually delete the object from the cache.. rest u can get the answer from above link