How JPA manage entities accross all same application instances?
How JPA manage entities accross all same application instances?
I have some confusing things about JPA.
As far as I know, JPA has persistence context(aka. L1 cache) and It manages all entities for persistence. and It manages entity with the below process.
1. when the find query occurs, there is no entity in context, so entity manager request data to the database
2. save the result as entities in persistence contentext.
3. after this, when the query occurs, persistence query return memory entities if they have.
But in 3rd, It is quite confusing how it works in multiple instances environment. I think, in multiple application instances, It can't ensure same entity data across all instances.
Let's assume that there are 2 instances of JPA application.(all instances are same logic for load balance). table has 2 column, one is id, primary key, and the other is name varchar.
There are a row which is id=1, name="foobar"
"instance A" generate entity which is ID equal 1 from database by user select query.
also "instance B" generate same entity which is ID equal 1 from database by user select query.
and then "instance A" update entity which is ID=1 to name="blahblah" by user update query.
After enough time later with no query to both instances, if update query which is "update name set newname from table where name=blahblah" occurs in "instance B", I'm confused, It has already the entity and its name may not updated to "blahblah". so How does the last update query work in JPA?
EDIT
I realized that my question is not clear. Because JPA execute DB query to DBMS when the transaction was commited, Usually there is no problem how many applications are.
To tell you why I ask this, let's assume that there is below code.
void updateEntities()
entityManager.getTransaction().begin();
List<MyEntity> entities = dao.findAll(); // point1
for (MyEntity e : entities)
e.setValue(e.getValue() + 100); // point2
entityManager.getTransaction().commit();
List<MyEntity> findMyEntities()
return dao.findAll(); // point3
Two instance which has above code block in their code(both are same code instances for load balancing). (and the number of entities are enough number for RAM.)
when A instance
generate entities in memory when findMyEntities
method was called by client query.
then next query was occured by client, then the request reached to instance B
, and the instance B
also generated all entities in memory.
and then update query reached to instance A
and instance executed updateEntities and all entities in memory of instance A
were updated.
but in this time, There are difference between instance A
's cached entities and instance B
s cached entities. But instance B
may not be able to know the data was updated or not.
A instance
findMyEntities
instance B
instance B
instance A
instance A
instance A
instance B
instance B
So I wondered when the update query is occured to instance B
after above situation, I believed like below
instance B
updateEntities
Is it correct?
If you have 2 unconnected applications then JPA (in app1) will not know of any updates that have happened in app2, unless they are sharing the same (external) L2 cache of course. But then the log would tell you where objects are coming from
– Billy Frost
Aug 31 at 7:57
3 Answers
3
This is about transaction isolation and lock. If you want to see changes committed by other transactions, refresh(entity) is needed. JPA does not know about changes committed by other transactions.
Class of the bean, is usually marked with:
@Stateless without status, that is, it does not save the state even if another bean requests the same information.
You can read:
https://www.tutorialspoint.com/ejb/ejb_stateless_beans.htm
@StateFul with status, will save the state, and it will not change until the bean ends the transaction.
You can read:
https://www.tutorialspoint.com/ejb/ejb_stateful_beans.htm
And read this:
https://docs.oracle.com/javaee/6/tutorial/doc/gipjg.html
In addition to this, you can have the methods(through the EntityManager and EntityTransaction):
rollback
flush
refresh
commit
setFlushMode () that can have two values, AUTO and COMMIT
See an example:
EntityManager em = ....
EntityTransaction et = em.getTransaction();
et.begin();
try
em.persist(someObject);
et.commit();
et.rollback();
Finally you can specify the type of transaction you want to use in your bean, these can be:
MANDATORY
REQUIRED
REQUIRES_NEW
SUPPORTS
NOT_SUPPORTEED
NEVER
To use this attribute:
@TransactionAttribute(TransactionAtributeType.NEVER)
public float division(float a,float b)
return (a/b);
This question is originated from my misunderstanding about JPA L1 cache life.
The L1 cache is invalidated when the transaction was committed or client request was over(in OSIV).
So In my point, the L1 cache is not shared with thread or process.
It is valid only a same transaction or same request in OSIV.
So there is no problem if the instances are multiple or not.
I appreciate someone who answered the stupid question.
Thanks for contributing an answer to Stack Overflow!
But avoid …
To learn more, see our tips on writing great answers.
Some of your past answers have not been well-received, and you're in danger of being blocked from answering.
Please pay close attention to the following guidance:
But avoid …
To learn more, see our tips on writing great answers.
Required, but never shown
Required, but never shown
By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.
I believe that JPA "knows" when a refresh on the underlying entity is necessary, i.e. it knows when it has to refresh from the database.
– Tim Biegeleisen
Aug 31 at 3:16