Question

I have a JUnit Test where I set up the test data in the beginning of the test case, and then test for the conditions of the test case afterward in the same test method. The query that tests the conditions of the test case is a native query. I know that I have to explicitly call EntityManager.flush() in order for my inserts/updates to be written immediately to the DB since they are in the same transaction. Additionally, I noticed that I can replace entityManager.flush() with a JPA query, which seems to achieve the same thing. I have heard that JPA will cache DB operations in the same transaction until there is a need to execute them immediately, such as when select queries are issued. So this all makes sense. My question is, why doesn't this behavior also apply to native queries? Here my native query does not trigger the immediate execution of insert/updates in testSetup(), thus causing my assert to fail.

@Test
@Transactional
public void testCase() {
    testSetup();
    entityManager.flush();  // can be replaced with entityManager.createQuery("from Person");

    List resultList = entityManager.createNativeQuery("select * from Person").getResultList();
    Assert.assertTrue(resultList.size() == 1);
}
Was it helpful?

Solution

tl;dr - native queries bypass the persistence context and the cache.

This includes the queries you create by calling createNativeQuery, obviously. But bulk updates (UPDATE and DELETE), though expressed in JPQL are translated to native queries by the provider and bypass the persistence context and the cache as well.

Thus flushing or executing other queries will not have the expected effect.

Besides, if your native queries have changed the data on entities that are managed in the current persistence context or are cached, the entities will not be refreshed automatically and will become stale.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top