Suggested Pages

Tuesday, July 31, 2012

JPA Persistence context as First Level Cache


The Persistence Context is a set of entities in the Managed State. Entities in Persistence Context have a unique persistent identity and these entities are used to synchronize objects in memory with objects in the database.
In this post we'll see how the Persistence Context acts like a first level cache.

Code Example


GenericDAO.java
....

@Repository
public class GenericDAO {

 @PersistenceContext(unitName = "persistenceUnitTest",type=PersistenceContextType.TRANSACTION)
 private EntityManager entityManager;


 @Transactional(propagation = Propagation.REQUIRED)
 public void saveRequired(Child child) {
  entityManager.persist(child);
 }
 @Transactional(propagation = Propagation.REQUIRED)
 public Child findByIdRequired(int childId) {
  return entityManager.find(Child.class, childId);
 }

 @Transactional(propagation = Propagation.REQUIRED)
 public Child saveAndFindRequired(Child child) {
  entityManager.persist(child);   
  return entityManager.find(Child.class, child.getChildId());
 }
 
}


DAOTest.java
...

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(value = "DAOTest-context.xml")
public class DAOTest {

 @Autowired
 private GenericDAO genericDAO;

 @Test
 public void testSaveDifferentPersistentContext() {
  System.out.println("------------testSaveDifferentPersistentContext(): start -------");
  Child child = new Child();
  child.setName("child");
  child.setChildId(1);
  genericDAO.saveRequired(child);
  Child findById = genericDAO.findByIdRequired(child.getChildId());
  System.out.println(findById);
  System.out.println("------------testSaveDifferentPersistentContext(): end -------");
 }
 
 @Test
 public void testSaveSamePersistentContext() {
  System.out.println("------------testSaveSamePersistentContext(): start -------");
  Child child = new Child();
  child.setName("child");
  child.setChildId(2);
  Child childFound = genericDAO.saveAndFindRequired(child);
  System.out.println(childFound);
  System.out.println("------------testSaveSamePersistentContext(): end -------");
 }
 
}




testSaveDifferentPersistentContext() is not using Persistence Context as First Level Cache


As you can see the method testSaveDifferentPersistentContext() calls saveRequired() and findByIdRequired() methods of GenericDAO. So this is what it happens:
  1. When the method saveRequired() starts, a new transaction is created;
  2. When the method persist() of the EntityManager is invoked, a new persistence context is created. Then the child entity is inserted into this persistence context;
  3. When the method saveRequired() ends, the persistence is flushed and the transaction goes to commit;
  4. the method findByIdRequired() starts and a new transaction is created;
  5. When the method find() of the EntityManager is invoked, a new persistence context is created. Then the child entity is searched in the persistence context but it's not found;
  6. the method find() retrieves the entity by performing a query on the database.

From the database point of view, let's see the query executed.

insert into Child (name, parent_parentId, childId) values ('child', '', 1)

  select
        child0_.childId as childId1_1_,
        child0_.name as name1_1_,
        child0_.parent_parentId as parent3_1_1_,
        parent1_.parentId as parentId0_0_,
        parent1_.name as name0_0_ 
    from
        Child child0_ 
    left outer join
        Parent parent1_ 
            on child0_.parent_parentId=parent1_.parentId 
    where
        child0_.childId=1



As you can see, an INSERT and a SELECT are performed. This happens because the entity searched is not present in the persistence context (that acts as a first level cache) so you need to hit the database,

testSaveSamePersistentContext() is using Persistence Context as First Level Cache


The method testSaveSamePersistentContext() calls only the method saveAndFindRequired() of GenericDAO.
  1. When the method saveAndFindRequired() starts, a new transaction is created;
  2. When the method persist() of the EntityManager is invoked, a new persistence context is created. Then the child entity is inserted into this persistence context;
  3. When the method find() of the EntityManager is invoked, a new persistence context is created. Then and the child entity is searched in the persistence context and it's found because it has just been inserted;
  4. when the method saveAndFindRequired() method ends, the persistence is flushed and the transaction goes to commit.
From the database point of view, let's see the query executed.

insert into Child (name, parent_parentId, childId) values ('child', '', 2)

As you can see only an insert is performed. This happens because the entity searched is present in the persistence context (that acts as a first level cache) so you don't need to hit the database.

No comments :

Post a Comment

Suggested Pages