When does EntityManager commit? - jpa

I have the following service...
#Stateless
#LocalBean
public class RandomService {
#EJB RandomString stringTokenizer;
#PersistenceContext
EntityManager em;
public String generate(Actions action)
{
Token token = new Token();
token.setAction(action);
token.setExpiry(new Date());
token.setToken(stringTokenizer.randomize());
em.persist(token);
//em.flush();
return String.format("%010d", token.getId()) + token.getToken();
}
}
If I do not put em.flush() then the line token.getId() will return null (Using DB GENERATED SEQUENCE) though I know if I return Token instead of string to the calling service the id is set. So it seems that EM flushes when the service returns a token object but not when I put String. By putting flush I get what I need is that right though?

Do not confuse flushing with committing. During flush() JPA provider physically sends generated SQL to the database and, in your case, reads the generated ID and populates it in the bean. Note that you should always use the returned entity rather than the original one passed to persist():
token = em.persist(token);
Committing, on the other hand, performs database commit. Obviously it will trigger flush() first, but it won't help you here. But since you are asking - every method in EJB is transactional by default. This means the transaction is committed when you leave the first EJB on the stack: if you call one EJB from another, the callee joins the caller transaction by default (see: transaction propagation behaviour).
Also note that the rules when to flush() are a bit complicated since every provider tries to do this as late as possible and in batches.

Related

Spring data JPA and repeated findById calls with same Id on non Transactional method

working with Spring data JPA and having this method in a #Service class
#Transactional(propagation = Propagation.NEVER)
public void getClientBydIdThreeTimes() {
clientRepository.findById(1L);
clientRepository.findById(1L);
clientRepository.findById(1L);
}
will it hit the database three times? It shouldnt because there is not
transactional environment(propagation = Propagation.NEVER) and each
query its a transaction itself and therefore each time the query is
executed, and entityManager is created having its own persistent
context, right?
I am having a wierd behaviour because when I make an http request and this method is executed, only the first query is sent to the database caching the next two calls but if I call this method from inside my application(like a Spring batch task), there are three sql sent to the database. I dont understand it, it should have the same behaviour, right?
Thanks

JPA/EclipseLink handling of #Version

In an application using EclipseLink 2.5 and container-managed transactions that needs to merge detached entities from time to time, each entity contains a field with the #Version annotation. Some implementation of optimistic locking is necessary, since enitities are mappted to DTOs and sent to the client, which might then request an update on these entities based on the changes they have made to the corresponding DTOs. The problem I am facing is that whenever persist() or merge() are called on an entity, the corresponding entity being added to the persistence context in the case of persist() or the updated entity returned by merge() do not contain the updated version field. To demonstrate this through an example, suppose we have the following entity:
#Entity
public class FooEntity implements Serializable {
#Id
#GeneratedValue(generator = "MyGenerator")
private Long fooId;
#Version
private Long version;
#Column(nullable = false)
private String description;
// generic setters and getters
}
This entity then gets persisted/merged in an EJB in a fashion similar to the following:
#Stateless
public class FooEjb {
#PersistenceContext(unitName = "FooApp")
private EntityManager entityManager;
public FooEntity create() {
FooEntity entity = new FooEntity();
entity.setDescription("bar");
entityManager.persist(entity);
return entity;
}
public FooEntity update(Long fooId, String description) {
FooEntity entityToUpdate = entityManager.find(FooEntity.class, fooId);
if (entityToUpdate != null) {
entityToUpdate.setDescription(description);
return entityManager.merge(entityToUpdate);
}
return null;
}
}
Calling these EJB methods shows the following behavior:
FooEntity newEntity = fooEjbInstance.create();
newEntity.getFooId(); // returns the generated, non-null value; for the sake of example 43L
newEntity.getVersion(); // returns null
entityManager.find(FooEntity.class, 43L).getVersion(); // returns 1L
// entity with fooId == 42L exists and has a version value of 1L
FooEntity updatedEntity = fooEjbInstance.update(42L, "fhtagn");
updatedEntity.getVersion(); // returns the old value, i.e. 1L
entityManager.find(FooEntity.class, 42L).getVersion(); // returns 2L
This makes the returned entity unsuitable for passing to the client, as any state changes made by the client cannot be persisted due to the merge/persist call rightly causing an OptimisticLockException.
The EJB methods are not explicitly annotated with #TransactionAttribute, which per JPA specs should cause the default value of TransactionAttributeType.REQUIRED to be applied. The current theory is that the phenomenon perceived here has to do with the version field being updated only when the transaction is committed. Since by the time one of the EJB methods above returns, its associated transaction has not yet been committed (and will in fact be committed immediately after the method returns), the version field has not yet been updated. There was a mention of in object vs. in cache storing of the version filed in this question, but I have not been able to find definitive documentation on this. Is this as a whole working as designed, either according to JPA 2.0 or the EclipseLink implementation? If so, how could I best deal with the aforementioned problem?
Merge and persist don't need to immediately go to the database, so operations that depend on, triggers, sequencing and versions might need to call flush or commit to have those values set. Flush forces the context to synchronize with the database, and should set the values appropriately in managed objects. ID generation can be set on persist calls - this can happen when sequences allow for pre-allocation, but not usually when identity objects or triggers are used.
Since an EntityManager context represents a transaction, it is completely isolated from other contexts/transactions. Until the transaction commits, version and other changes cannot be picked up by other processes anyway, so it shouldn't matter when synchronization occurs to other processes. JPA states that most exceptions occur either on the persist/merge call or can be delayed until the context synchronizes with the database (flush/commit) depending on the nature of the operation. Optimistic locking is meant for systems where these collisions are infrequent and retries are less expensive than pessimistic locking every operation

Transaction needed if multiple EJB methods called?

My question is about the need to define a UserTransaction in a JSF Bean if multiple EJB methods are called.
This is my general scenario:
//jsf bean...
#EJB ejb1;
...
public String process(businessobject) {
ejb1.op1(businessobject);
ejb1.op2(businessobject);
....
}
both ejbs methods manipulate the same complex jpa entity bean object (including flush and detachment). I recognized in the database that some of the #oneToMany relations form my entity bean where duplicated when ejb1.op1() is called before ejb1.op2().
I understand that both ejbs start a new transaction. And to me anything looks ok so far.
But the JSF code only works correctly if I add a UserTransaction to my jsf method like this:
//jsf bean...
#Resource UserTransaction tx;
#EJB ejb1;
...
public String process(businessobject) {
try {
tx.begin();
ejb1.op1(businessobject);
ejb1.op2(businessobject);
finaly {
tx.commit();
}....
}
I did not expect that it is necessary to encapsulate both ejb calls into one usertransaction. Why is this necessary?
Each #Stateless EJB method call from a client (in your case, the JSF managed bean), counts by default indeed as one full transaction. This lasts as long as until the EJB method call returns, including nested EJB method calls.
Just merge them both into a single EJB method call if it must represent a single transaction.
public String process(Entity entity) {
ejb1.op1op2(entity);
// ...
}
with
public void op1op2(Entity entity) {
op1(entity);
op2(entity);
}
No need to fiddle with UserTransaction in the client. In a well designed JSF based client application you should never have the need for it, either.
As to the why of transactions, it locks the DB in case you're performing a business action on the entity. Your mistake was that you performed two apparently dependent business actions completely separately. This may in a high concurrent system indeed cause a corrupted DB state as you encountered yourself.
As to the why of transactions, this may be a good read: When is it necessary or convenient to use Spring or EJB3 or all of them together?
Is a user transaction needed for you? Generally, container managed transactions are good enough and serve the purpose.
Even if you need to have user managed transactions, it is not a good to have transaction management logic mingled with JSF logic.
For using container managed transactions, you should look at using the #TransactionAttribute on the EJBs.
If all the methods in your ejb need to have the same level of transaction support, you could have the annotation at the class level. Else you could also use the #TransactionAttribute annotation against each individual ejb method.

Force 'reload' of JPA EntityManager in integration test

In a Spring-enabled integration test, I need to force the EntityManager to re-read from the database.
#Test
#DataSet("/xml/dbunit/truncate-tables.xml")
public void createTerminalFromQuery() {
// there should be zero terminals in the empty database
Assert.assertEquals(0, terminalService.countTerminals());
// makes remote REST call updating database outside the application's EntityManager
HttpEntity<QueryResponse> result = simulateRequest("query");
// attempts to force re-read of updated database (unsuccessfully)
entityManagerService.getEntityManager().flush();
// there should be exactly one Terminal in the database
Assert.assertTrue(terminalService.existsTerminalBySerialNumber(EXISTING_TERMINAL_SERIAL_NUMBER));
}
It has been verified that the Terminal is created and exists in the database. Despite this, the second assertion fails. When the first assertion is commented out, the second one is OK.
The test framework is Unitils/DBUnit and injecting an EntityManager via #PersistenceContext is difficult, as the required package unitils-orm depends on Spring 2.5 and JPA 1.0 leading to other problems.
Instead, I have created the EntityManagerService and verified that it indeed uses the same EntityManager as the TerminalService.
I have tried EntityManager.clear() and flush() and evicting the Cache from the EntityManagerFactory - but nothing seems to have any effect.
Any suggestions?
It's not clear how do you manage transactions. Since clear() doesn't help, perhaps both checks are executed inside the same transaction that doesn't see result of the transaction committed by the REST service.
Try to execute checks in different transactions.

JPA, scope, and autosave?

I am using JPA and lets say I do something like this
public class MoRun extends Thread {...
public void run() {
final EntityManagerFactory emFactory = Persistence.createEntityManagerFactory("pu");
EntityManager manager = emFactory.createEntityManager();
manager.setFlushMode(FlushModeType.COMMIT);
someMethod(manager);
...
}
public void someMethod(EntityManager manager){
Query query = manager.createNamedQuery("byStates");
List<State> list = query.getResultList();
for (State state : list) {
if(someTest)
state.setValue(...)
}
...
}
So for those objects that pass "someTest" and values are updated are those changes automatically persisted to the db even though there is no transaction and I don't explicitly "manager.save(state)" the object? I ask because it seems like it is and I was wondering if the flush is doing it?
According to the javadoc of FlushMode (I'm assuming this is a JPA 1.0 question), and as pointed out by #Konrad:
If there is no transaction active, the persistence provider must not flush to the database.
Since you're very likely using a transaction-type="RESOURCE_LOCAL" for your persistence unit, since I don't see any begin/commit surrounding your calls to your EntityManager (which is not good, more on this just after), for me there is no transaction active so I wouldn't expect anything to be flushed.
Anyway, as reminded in the nice JPA Concepts page:
With <persistence-unit transaction-type="RESOURCE_LOCAL">
you are responsible for EntityManager
(PersistenceContext/Cache) creating
and tracking...
You must use
the EntityManagerFactory to get an
EntityManager
The resulting
EntityManager instance is a
PersistenceContext/Cache
An
EntityManagerFactory can be injected via the
#PersistenceUnit annotation only (not #PersistenceContext)
You are
not allowed to use #PersistenceContext to refer to a unit
of type RESOURCE_LOCAL
You
must use the EntityTransaction API to begin/commit around every call to your
EntityManger
Calling
entityManagerFactory.createEntityManager()
twice results in two separate
EntityManager instances and therefor
two separate PersistenceContexts/Caches.
It is
almost never a good idea to have more than one instance of an
EntityManager in use (don't create a
second one unless you've destroyed the
first)
So, in my opinion, you should fix your code here, there is no real point at wondering about unexpected behavior if your code is not correct. Just performs calls to your EntityManager inside a transaction.
How do you know there is no transaction? Are you using it from EJB? In that case I bet there is a transaction.
From docs (http://java.sun.com/javaee/6/docs/api/javax/persistence/FlushModeType.html):
If FlushModeType.COMMIT is set, the
effect of updates made to entities in
the persistence context upon queries
is unspecified.
If there is no transaction active, the
persistence provider must not flush to
the database.
If you are in transaction, attached entities (i.e. those loaded in the same transaction) are automatically recorded to database.