First level cache not working with JPA and Hibernate

Tags: , , , ,



I an new to use hibernate caching (first level, 2nd level and query cache).

My project is configured using Spring MVC and JPA.

I am testing first level cache using JUnit test case below.

public class FirstLevelCacheTest
{
    private static final Logger logger = LoggerFactory.getLogger(FirstLevelCacheTest.class);

    @PersistenceContext
    private EntityManager       entityManager;

    @Test
    public void testFirstLevelCacheTest()
    {
        Long clientId = 1L;

        // fetch the client entity from database first time
        Client client1 = entityManager.find(Client.class, clientId);
        logger.debug("Client Name : {}", client1.getName());

        // fetch the client entity again
        client1 = entityManager.find(Client.class, clientId);
        logger.debug("Client Name : {}", client1.getName());
    }
}

And my entity class is defined as :

@Entity
@JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL)
@Table(name = "client")
public class Client extends BaseModel
{
    // instance variable declaration

    // getter and setter methods for instance variables
}

This should execute native query once in case first level cache is by default enabled. But I am getting result below while executing this query:

Hibernate: select client0_.id as id0_0_, client0_.created as created0_0_, client0_.createdBy as createdBy0_0_, client0_.updated as updated0_0_, client0_.updatedBy as updatedBy0_0_, client0_.contactNo as contactNo0_0_, client0_.contactPerson as contactP7_0_0_, client0_.contactPersonEmail as contactP8_0_0_, client0_.contactPersonNo as contactP9_0_0_, client0_.email as email0_0_, client0_.name as name0_0_ from client client0_ where client0_.id=?
[main] DEBUG Client Name : Client1
Hibernate: select client0_.id as id0_0_, client0_.created as created0_0_, client0_.createdBy as createdBy0_0_, client0_.updated as updated0_0_, client0_.updatedBy as updatedBy0_0_, client0_.contactNo as contactNo0_0_, client0_.contactPerson as contactP7_0_0_, client0_.contactPersonEmail as contactP8_0_0_, client0_.contactPersonNo as contactP9_0_0_, client0_.email as email0_0_, client0_.name as name0_0_ from client client0_ where client0_.id=?
[main] DEBUG Client Name : Client1

Below is my persistence related configurations:

@Configuration
@EnableTransactionManagement
public class PersistanceConfig
{
    // injection

    private String[] PACKAGES_TO_SCAN = new String[] { "com.mypackage1", "com.mypackage2" };

    @Bean
    public DataSource dataSource()
    {
        // dataSource setting 'com.mysql.jdbc.Driver' as a jdbc driver
    }

    private Properties jpaProperties()
    {
        Properties properties = new Properties();

        properties.put(AvailableSettings.DIALECT, hibernateDialect);
        properties.put(AvailableSettings.SHOW_SQL, hibernateShowSql);

        // 2nd level cache
        properties.put("hibernate.cache.use_second_level_cache", true);
        properties.put("hibernate.cache.region.factory_class", "org.hibernate.cache.ehcache.EhCacheRegionFactory");

        return properties;
    }

    @Bean
    public LocalContainerEntityManagerFactoryBean entityManagerFactory()
    {
        // entity manager settings using dataSource and jpaProperties
    }

    @Bean
    public JpaTransactionManager transactionManager()
    {
        // transaction manager settings using entityManagerFactory
    }
}

Can anybody help me to sort out an issue or anything I am doing wrong ?

Thanks in advance !

Answer

You need to annotate the test method with @Transactional or use the Spring TransactionTemplate.

Even if retrieving an entity doesn’t require a transaction, grouping multiple calls inside one would clearly specify the Persistence Context boundaries (where it is meant to start and where it should end).

To replicate the 1st Level Cache you need the same Unit Of Work throughout your test method, and annotating the test with @Transactional would start a transaction (a Spring logical transaction that’s bound to the current executing Persistence Context transaction which correlates to the actual physical database transaction).

When the test method ends the Transaction is usually roll-back so no changes will be propagated to any successive test, but within the currently executing test method you get to see your own changes, which is the Isolation property in ACID.



Source: stackoverflow