I have a JPA environment which has a Application-managed EntityManager. I manually create the entityManagerFactory and create the EntityManager from that. I would like to use the same EntityManager across multiple threads. The documentation says that EntityManager is not thread-safe, but all of my operations will only be reads and no writes will occur through the EntityManager. I also have a timeout on the data in the cache to ensure consistency. In such a scenario, is it ok to use the same instance of the EntityManager across threads? Or can there be any side effects / wrong data on using the same EntityManager across threads.
Thanks
To be sure, just lock the EntityManager instance where ever you use it by using synchronized.
So instead of writing
em.persist(...);
write
synchronized (em) {
em.persist(...);
}
You can read up about the locking mechanism here.
Related
I have a #Transactional method where I request a record using findById() from a Spring Data repository.
Now I want to lock this object in a way that other #Transactional methods if executed in parallel will wait until the lock is released.
What I tried: I went through the documentation of #Lock and LockModeType but I still can't figure out if it covers my case.
Another option would be select for update on a DB level, but I am not sure it is the best option.
Q: How to lock an Entity object (db row) in a spring data transaction and make other transactions wait?
What you want is called Pessimistic locking. Spring Data through JPA specification supports that. There are two modes of pessimistic locking available:
I think you are mixing up Transaction isolation with Locking. Through #Transactional annotation you can specify isolation which is applied to the connection, while through spirng-data #Locking you can define the locking mode. The Lock mode is not related to the transaction isolation specified on #Transactional. Effectively if the isolation is SERIALIZEABLE you would not need locking via JPA or spring-data, because the database will take care of it. The locks will be DB controlled in this case.
When you define locking the control is in your hands. Here is a description of the pessimistic lock types.
PESSIMISTIC_WRITE - all transactions including the read only ones will be blocked until the transaction holding the lock is complete. Dirty reads are not allowed.
PESSIMISTIC_READ - when you have this mode , concurrent transactions can read the data of the locked row. All updates need to obtain PESSIMISTIC_WRITE lock.
On top of this you can specify a timeout for the locking transaction completion.
should I create an EclipseLink EntityManager per method call, store in thread local or guard with a lock?
Obviously it's initially created from entityManagerFactory.createEntityManager().
Which is best practise please?
With per method call I'm concerned with performance.
With thread local I'm concern about cache visibility between threads.
With guarding a single EntityManager with a lock I have the cost of a lock each time.
/I'm using JSE - so no EJBs, no injtection - just entityManagerFactory.createEntityManager() in a multi-threaded JSE app.
Thanks
EntityManagers are not thread safe, and are designed to represent a unit of work. Each method/thread should have its own unless participating in a larger transaction. It is also better to close/clear them at logical points because they maintain a cache of managed entities that can grow large with long lived EntityManagers. There are numerous posts on what the best way to go is outside and inside a container.
EclipseLink's EntityManager uses EclipseLink's native sessions and unitOfWork underneath, which will lazily fetch resources as required, and release them when done. But they can be configured to operate differently.
#Singleton EJBs like this:
#Singleton
public class MySingleton {
#PersistenceContext
private EntityManager em;
...
#Lock(LockType.READ)
public void doPersistanceAction() {
}
}
So all callers of MySingleton#doPersistanceAction() would use the same instance of EntityManager simultaneously. And persistence context with attached entitys will share between callers. And transaction started by one caller may be commited by another.
Whether the ejb container handle such a situation?
So all callers of MySingleton#doPersistanceAction() would use the same
instance of EntityManager simultaneously
Yes, but it isn't a preferred & isn't thread-safe. Instead you should inject EntityManagerFactory & then within method you can get EntityManager from it.
And persistence context with attached entitys will share between
callers
Yes, same EntityManager instance is shared.
And transaction started by one caller may be commited by another
LockType.READ : For read-only operations. Allows simultaneous access to methods designated as READ, as long as no WRITE lock is held.
Therefore, as you have read-only operation, it shouldn't matter, but you need to revisit design.
Whether the ejb container handle such a situation?
Container will be responsible for initialization, injection, concurrency etc. for singleton bean, but you have to utilize it correctly.
I have two (or more) Java Threads creating, updating and deleting entities from a mysql database using JPA. To achieve this I have a PersistenceLayer class creating the EntityManager and providing save, update and delete methods for all my entities looking like:
public void saveEntity(Entity entity) {
manager.getTransaction().begin();
manager.persist(entity);
manager.getTransaction().commit();
}
public void saveEntity2(Entity2 entity) {
manager.getTransaction().begin();
manager.persist(entity);
manager.getTransaction().commit();
}
If one thread enters operation saveEntity and the other saveEntity2 at the same time, both will try to get the transaction from the EntityManager wich will fail. However I always thought that the underlying database is able to manage multiple transactions, especially if both are working on different rows or even different tables. Of course I could synchronize the blocks, but that would mean only one DB connection is possible at a time which will not scale to multiple users creating several threads.
What wrong assumption am I doing here? Is it possible to submit multiple transactions to a database via JPA and let the DB handle concurrency issues?
EntityManager is not intended to be used by multiple threads. You need to obtain separate instances of EntityManager for each thread.
Actually, if you use EJB or Spring you can use a transaction-scoped EntityManager, which can be used from multiple threads (it's a proxy which delegates actual work to separate thread-bound instances of EntityManager), but I think it's not your case.
To handle concurrency issues when the object is being processed accross multiple transactions, lock can be acquired on the object. Either Optimistic or Pessimistic locking can be used with appropriate lock-modes.
Locking the versioned object by entityManager.lock(entity, LockModeType.READ) will ensure that it will prevent any Dirty Read & Non-Repeatable Read.
LockModeType.WRITE will force incrementing/updating the version column of the entity.
i have a swing desktop application that use a entitymanagerfactory, but when this application is executed many times at the same time, the diferents entity managers have old data that was modified by others and this changes will not visible until the next entitymanagerfactory... how can i sync in anytime the entitymanager with the database data??
EntityManager instances should not be held for prolonged periods of time; instead each should be used for unit of work and discarded afterwards.
That said, EntityManager has a refresh() method you can invoke to reload state of a particular entity from the database.
It also has a clear() method which will clear the persistence context completely of "old" data. You need to be careful with it, though - calling clear() without flush() will discard all pending updates.