问题
I'm writing some application for GlassFish 2.1.1 (JavaEE 5, JPA 1.0, as far as I know). I have the following code in my servlet (which I mostly borrowed from some sample on the Internet):
@PersistenceContext(name = "persistence/em", unitName = "pu")
private EntityManager em;
@Resource
private UserTransaction utx;
@Override
protected void doPost(...) {
utx.begin();
. . . perform retrieving operations on em . . .
utx.rollback();
}
web.xml
has the following in it:
<persistence-context-ref>
<persistence-context-ref-name>persistence/em</persistence-context-ref-name>
<persistence-unit-name>pu</persistence-unit-name>
</persistence-context-ref>
The problem is, the em doesn't see changes that have been made in another, outside transaction. Roughly, I make a request to my servlet from web browser, see data, perform some DML in SQL console, reload servlet page -- and it doesn't show any change. I've tried to use many combinations of em.flush
, and utx.rollback
, and em.joinTransaction
, but it doesn't seem to do any good.
Situation is complicated by me being a total newbie in JPA, so I do not have a clear understanding of how the underlying machinery works. So any help and -- more importantly -- explanations/links of what is happening there would be very appreciated. Thanks!
回答1:
The JPA implementation maintains a cache of entities that have been accessed. When you perform operations in a different transaction without using JPA, the cache is no longer up to date, and hence you never see the changes made in it.
If you do wish to see the changes, you will have to refresh the cache, in which case all entities will be evicted from the cache. Of course, you'll need to know when to do this (after the other transaction has completed), otherwise you'll continue to see ambiguous entities. If this is your business need, then JPA is possibly not a good fit to your problem domain.
Related:
- Are entities cached in jpa by default ?
- Invalidating JPA EntityManager session
回答2:
As axtavt says, you need to commit the transaction in the console. Assuming you did that, it is also possible data is still being cached by the PersistenceManager (or underlying infrastructure).
To prevent trouble with caching you can evict by hand (which may be tricky as you have to know when to evict) or you can go to pessimistic locking. Pessimistic locking can have a huge impact on performance, but if you have multiple independent connections to the database you may not have a choice.
If your process has concurrent read/writes from different sources the whole time, you may really need pessimistic locks. If you sometimes have a batch update from an external source, you may try to signal, from that batch job, your JPA application that it should evict. Perhaps via a web service or so. That way you would not incur pessimistic locking performance degradation the entire time.
The wise lesson here is that synchronization of processes can be really complicated :)
回答3:
Perhaps you need to commit a transaction made in SQL console.
来源:https://stackoverflow.com/questions/4416359/entitymanager-doesnt-see-changes-made-in-other-transactions