Force 'reload' of JPA EntityManager in integration test - jpa

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.

Related

Play Framework - JPA - #Transactional error?

I'm experiencing a very strange behaviour with Transactions using play-2.2.2 with JPA and Eclipse-Link.
My Controller-Action is annotated with #Transactional like this:
#Transactional
public static Result submitOrder() {
// class does call private Methods which persist some entities (methods not annotated)
//...
Action is calling private methods to persist data (This should happen in the same transaction since no other Transaction is started).
During the Methods calls (at random locations) data gets written to db (inserts and updates). Debuging shows that the same (active) transaction is used before and after the write. EntityTransactionImpl:commit is never executed and transaction stays active until request is finished ( watched play.db.jpa.JPA.em().getTransaction() )
How is it possible that the data is written although transaction is still active?
It breakes the setRollbackOnly Mechanism since already written data isn't rolled back.
May there be any kind of Timeout that issue these writes.
Can you suggest any debug-entry-point to narrow down the problem (where can i start debuging the actual write-operations, if not in EntityTransactionImpl:commit)?
Dependencies in build.sbt
persistence.xml
The above described behaviour seemed very odd at first, but then i read about FlushMode and now it makes sense.
The FlushMode of eclipselink as well as hibernate is set to FlushModeType.AUTO
FlushModeType.AUTO automatically flushes Entities to the DB when it thinks it's neccessary. This can be because of an readable operation (Query) on a Persited (but not flushed) Entity but it also happened somehow randomly during my observations.
This breaks the rollback-on-failure mechanism, which I thought must be the standard behaviour of #Transactional.
To achive a propper rollback (on failure or if setRollbackOnly() is set), of all persisted but not flushed entities on transcaction commit, you have to explicitly set the FlushMode at the beginning of your Action.
JPA.em().setFlushMode(FlushModeType.COMMIT);
If you're using Eclipselink, you can also set the following property to make it default behaviour:
<property name="eclipselink.persistence-context.flush-mode" value="commit" />
Links which helped me understand:
Eclipselink Context Flushmode
what to use flush mode auto or commit
performance tuning hibernate

JPA/EclipseLink: Does EntityManager.getTransaction() create a new transaction or return the active one?

I am using EclipseLink 2.3.0. I have a method that I am calling from a unit test (hence outside of a container, no JTA) that looks like this:
EntityManager em = /* get an entity manager */;
em.getTransaction().begin();
// make some changes
em.getTransaction().commit();
The changes were NOT being persisted to the database, and looked at this for a long time and finally realized that EntityManager.getTransaction() is actually returning a NEW EntityTransaction, rather than the same one in both calls. The effect is that the first call creates a new transaction and begins it, and the second call creates ANOTHER transaction and commits it. Because the first transaction was never committed, the changes are not saved. We verified this like this:
log.info(em.getTransaction().toString());
log.info(em.getTransaction().toString());
Which resulted in these log messages:
INFO: org.eclipse.persistence.internal.jpa.transaction.EntityTransactionImpl#1e34f445
INFO: org.eclipse.persistence.internal.jpa.transaction.EntityTransactionImpl#706a4d1a
The two different object ID's verifying that there are two different instances. Changing the code to this:
EntityManager em = /* get an entity manager */;
EntityTransaction tx = em.getTransaction();
tx.begin();
// make some changes
tx.commit();
... remedied the problem. Now when I run the code, I see the SQL statements generated to do the database work, and looking in the database, the data has been changed.
I were a bit surprised by this outcome, since I have seen numerous code examples online (for JPA generally and for EclipseLink specifically) that recommend the code we used for managing transactions. I searched far and wide for information specifically about this but have not found anything. So what's going on?
I looked in the JPA spec for something that specifies exactly what getTransaction() does and it was not specific if the transaction is new or the same. Is there a setting in persistence.xml that controls this? Is the behavior specific to each implementation of the JPA spec?
Thanks so much for any information or guidance.
Using getTransaction() does work in JPA and in EclipseLink (this is how our own tests work).
My guess is you are doing something else very odd.
Are you using Spring, or another layer?
Please include the entire code and persistence.xml for your test. Ensure that you are not using JTA in your persistence.xml.
The JPA spec (see paragraph 7.5.4) has explicit examples showing the use of getTransaction() to begin and commit the transaction. So your code should be fine.
Your test shows that you get two different objects, but that doesn't mean the same transaction is not used. Maybe the returned object is just some proxy to a single, real, transaction object.
Or maybe the transaction is committed or rollbacked inside the code hidden under // make some changes.
Have u tried to use persist before commit: ?
Employee employee = new Employee("Samuel", "Joseph", "Wurzelbacher");
em.getTransaction().begin();
em.persist(employee);
em.getTransaction().commit();

How to persist JPA entities even when EJB method throws an exception?

I have an EJB, whose method (among other things) persists JPA entity. If the method throws an error, the transaction is rolled back and the entity is not persisted.
However, I do want that entity to be persisted regardless of any exceptions, that might occur in the EJB method.
I'm using WebSphere 7.0, EJB3.0, JPA 1.0 (OpenJPA that is in WAS), DB2, if it matters.
I tried setting #TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED) on top of EJB; with that, entity is not persisted even if there is no exception. I also tried commiting transaction myself (em.getTransaction().commit()), but getTransaction() throws exception (because transactions are managed by container).
Use bean-managed transactions.
#Stateless
#TransactionManagement(TransactionManagementType.BEAN)
public class MyEJB {
#PersistenceContext(unitName="...")
private EntityManager _em;
#Resource
private UserTransaction _utx;
public void myEJBMethod() {
_utx.begin();
// Use _em
_utx.commit();
// Do other work that might throw an exception.
}
}
Alternatively, use TransactionAttributeType.REQUIRES_NEW as suggested by edalorzo.
I am not an expert on EJBs, but I have been dealing with JPA and transactions for a few days now.
I recently answered another question about how entities resided in a context, and how this works in Java EE applications, the context is linked with your JTA transaction.
You can see details of this answer by clicking here. I think it is useful to understand how to context works in order to comprehend the nature of problems like the one you describe.
If you do not provide transaction support, then there is nothing to persist from the container standpoint, and therefore, your changes to the context are transient.
Also you have to consider that once an exception occurs, your context becomes invalid, and the entities in it get detached. (There are a few exceptions to this, like NoResultException).
Thus, from that point on, if you want to commit something, you need a new JTA transaction, with a new fresh JPA context in order to be able to commit changes to the database.
As I said, I am not an expert in EJBs, but if your method fails due to exceptions and you still would like to retry the transaction again by re-invoking the method, then you could force a new transaction to be created every time the method is invoked and by this, you would create a new fresh JPA context.
On the other hand, if you want your modifications to the entities to be persisted, regardless of exceptions in the method, then you might like to consider moving the code that is updating the entities to a new EJB method defined to start a new transaction (TransactionAttributeType.REQUIRES_NEW) every time you invoke it.
By the time this second inner method finishes, your work over the transactions will be automatically flushed to the database, regardless of the outer method of you EJB failing.
Basically, you would be providing a new context for your entities, and linking such context to a new transaction, scoped to commit when the inner method completes.
The natural behavior in EJB containers, as far as I understand, is that ever method joins the already existing transaction, and this is what you might like to prevent, from my point of view.
Another alternative: if you want to control your context using a different transaction support then you might like to consider providing a resource-local based persistence unit and you can manually instantiate your entity manager and control transaction scope as you wish. But honestly, this does not sound like a good idea to me, at least no in the context of the problem that you described.

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.

JPA NamedQuery does not pick up changes to modified Entity

I have a method that retrieves Entities using a NamedQuery. I update a value of each entity and then run another named query (in the same method and Transaction) filtering by the old value and it returns the same Entities as if I had not changed them.
I understand that the EntityManager needs to be flushed and also that it should happen automatically but that doesn't make any difference.
I enabled hibernate SQL logging and can see that the Entities are not updated when I call flush but when the container transaction commits.
EntityManager entityManager = getPrimaryEntityManager();
MyEntity myEntity = entityManager.find(MyEntityImpl.class, allocationId);
myEntity.setStateId(State.ACTIVE);
// Flush the entity manager to pick up any changes to entity states before we run this query.
entityManager.flush();
Query countQuery = entityManager
.createNamedQuery("MyEntity.getCountByState");
// we're telling the persistence provider that we want the query to do automatic flushing before this
// particular query is executed.
countQuery.setParameter("stateId", State.CHECKING);
Long count = (Long) countQuery.getSingleResult();
// Count should be zero but isn't. It doesn't see my change above
To be honest I'm not that familiar with JPA, but I ran into similar problems with Hiberate's session manager. My fix was to manually remove the specified object from Hibernate's session before querying on it again so it's forced to do a lookup from the database and doesn't get the object from cache. You might try doing the same with JPA's EntityManager.
I've just had the same issue and discovered two things:
Firstly, you should check the FlushMode for the persistence context
and / or the query.
Secondly, make sure that the entity manager is
exactly the same object for both transaction management and query
execution. In my case, I had Mockito spy on the entityManager, which
was enough to break the transaction management.