Skip to content

Hibernate Dynamic SQL Cache module - allows to keep sql cache up-to-date

License

Notifications You must be signed in to change notification settings

mrniko/hibernate-dsc

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

11 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

#Hibernate Dynamic SQL Cache Overview

Dynamic Sql Cache module for Hibernate 4+.

The module has been succesfully used in number of projects those running under heavy load. The reason to create this project is inefficient Hibernate query caching mechanism. Key disadvantages of Hibernate caching system:

  1. Any (INSERT, UPDATE, DELETE) operation runned on any Entity-table clears hql cache assigned to hql-query or entity collection. This nullifies the benefits of using HQL-cache and entity-collection cache in case of huge amount of queries.
  2. SQL-cache holds result of first query invocation only and holds it forever, there is no way to reset it.

This project implements dynamic sql-query caching by updating results on every INSERT or DELETE operation for entity-table used in SQL-query. To take advantage of dynamic sql cache you should change your look towards sql-query creation:

  1. Query should return only entity ID, because you can always load it from entity-cache by ID. (Two cache read operations much faster than database READ operation)
  2. Use only immutable properties of entity as query parameters.
  3. Use dynamic sql-query cache instead of any entity-collections.

Licensed under the Apache License 2.0.

Features

  • Compatible with any cache provider (EHCache, Infinispan, Hazelcast ...)
  • Test cases included

#Usage example

This example uses "Spring Framework", but you can use project without it.

Somethere in hibernate.cfg.xml

  ...

  <property name="hibernate.cache.query_cache_factory">com.corundumstudio.hibernate.dsc.DynamicQueryCacheFactory</property>

  <property name="hibernate.cache.region.factory_class">org.hibernate.cache.infinispan.InfinispanRegionFactory</property>
  <property name="hibernate.cache.use_second_level_cache">true</property>
  <property name="hibernate.cache.use_query_cache">true</property>

  ...

Note: you can use any other cache factory not only org.hibernate.cache.infinispan.InfinispanRegionFactory

@Configuration
public class QueryCacheListenerConfig {

    @Bean
    public QueryCacheEntityListener createCacheListener() {
            return new QueryCacheEntityListener();		
    }

    @PostConstruct
    protected void init() {

            // register hibernate dynamic cache listener
            // QueryCacheEntityListener

            EventListenerRegistry registry = sessionFactory.getServiceRegistry().getService(EventListenerRegistry.class);
            registry.getEventListenerGroup(EventType.POST_UPDATE).appendListener(createCacheListener());
            registry.getEventListenerGroup(EventType.POST_INSERT).appendListener(createCacheListener());
            registry.getEventListenerGroup(EventType.POST_DELETE).appendListener(createCacheListener());
    }

}

Entity DAO example:

@Service
public class SimpleEntityDao {

    private final String queryRegionName = "SimpleEntity_Query";
    private final String query = "SELECT id FROM SimpleEntity WHERE phone = :phone";

    @Autowired
    private QueryCacheEntityListener queryListener;
    @Autowired
    private SessionFactory sessionFactory;

    @PostConstruct
    protected void init() {

            // here is our cache callback
            // invokes on every "insert" or "delete" operation 
            // for SimpleEntity object and keeps query result up-to-date

    	CacheCallback<SimpleEntity> handler = new CacheCallback<SimpleEntity>() {

    		@Override
    		protected void onInsertOrDelete(InsertOrDeleteCommand command,
    				SimpleEntity object) {
    			command.setParameter("phone", object.getPhone());
    			command.setUniqueResult(object.getId());
    		}

    	};
    	queryCacheEntityListener.register(SimpleEntity.class, queryRegionName, handler);
    }
    
    @Transactional
    public SimpleEntity getEntityByPhone(String phone) {
            Session session = sessionFactory.getCurrentSession();
            SQLQuery sqlQuery = session.createSQLQuery(query);
            sqlQuery.addScalar("id", LongType.INSTANCE);
            sqlQuery.setCacheable(true);
            sqlQuery.setCacheRegion(cacheRegionName);
            sqlQuery.setParameter("phone", phone);
            Long idResult = (Long) sqlQuery.uniqueResult();      
            return session.get(SimpleEntity.class, idResult);
    }

    ...
    
    create, delete methods...

}	

About

Hibernate Dynamic SQL Cache module - allows to keep sql cache up-to-date

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages