-->
These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 2 posts ] 
Author Message
 Post subject: Cache ignored, Spring 4 @Transactional, Hibernate 4, ehcache
PostPosted: Sat Apr 19, 2014 4:08 pm 
Newbie

Joined: Sat Apr 19, 2014 4:04 pm
Posts: 2
Hi all,

I'm blocked since a few days with Hibernate caching in a Spring context using @Transactional annotations.

I tried all the solutions found on the web without success...

The single solution that work is to use the @Cacheable Spring annotation (from spring-context-support), but I'm not satisfied because I cannot use the Hibernate @Cache annotation on my entities.
@Cacheable can just be used on methods like services methods, and I retrieve entities without methods...

For exemple:

I call the following service that fetch a CollectionEntity
Code:
    @Override
    @Transactional(readOnly = true)
    public CollectionEntity getById(Integer collectionId) throws Exception {
        if(collectionId < 1) {
            logger.debug("Cannot retrieve a collection from identifier inferior to 1.");
            return null;
        }
        return collectionDao.getById(collectionId);
    }


A CollectionEntity contains a ProgramEntity set
Code:
    @OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
    @JoinTable(name = CollectionProgram.TABLE, joinColumns = { @JoinColumn(name = COLUMN_COLLECTION_ID, referencedColumnName = CollectionProgram.COLUMN_COLLECTION_ID) }, inverseJoinColumns = { @JoinColumn(name = CollectionProgram.COLUMN_PROGRAM_ID, referencedColumnName = ProgramEntity.COLUMN_PROGRAM_ID) })
    private Set<ProgramEntity> programs = new HashSet<ProgramEntity>(0);


These programs contain a ProgramBroadcasting set
Code:
    @OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
    @JoinColumn(name = ProgramBroadcastingEntity.COLUMN_PROGRAM_ID)
    private Set<ProgramBroadcastingEntity> broadcastings = new HashSet<ProgramBroadcastingEntity>(0);


And these programs broadcasting contain a ChannelEntity (a referential data)
Code:
    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(name = COLUMN_CHANNEL_ID, nullable = false)
    private ChannelEntity channel;


So if I want to cache the ChannelEntity, I normally just need to put the following annotation on its class.
Code:
    @Entity
    @Cache(usage = CacheConcurrencyStrategy.READ_WRITE, region = "Channel")
    @Table(name = ChannelEntity.TABLE)
    public class ChannelEntity implements java.io.Serializable {


The "EAGER" fetching is a very attractive solution for referential data! But if a want to use @Cacheable, which is at the moment the only solution, I must declare the ChannelEntity with FetchType.LAZY and write a service class to put the @Cacheable on it just to cache this data.
It's a joke... I won't do it for all my referential data classes...


A real solution is just to have a working Hibernate @Cache annotation to put on the ChannelEntity.


To get it functional, I even have developed my own "SingletonEhCacheRegionFactory" class initialize with the Spring class "EhCacheManagerFactoryBean" as cache manager.
And the data continue to be fetched from database. This solution worked for one of my colleagues, but with older versions of Spring (<4) and Hibernate (<4).
So, with the new versions, it doesn't seem to be a good solution...


So, I really need your help.


Before to give you my configuration, here are my quick tests on a main class to retrieve a ChannelEntity from database and then from cache.


Here the test is OK (it work):
Code:
    private static void testGetChannelFromCache2(BeanFactory factory) throws Exception {
        SessionFactoryImpl sessionFactoryImpl = ((SessionFactoryImpl) factory.getBean("sessionFactory"));
        Session session = sessionFactoryImpl.openSession();
        session.beginTransaction();
   
        ChannelEntity channel1 = (ChannelEntity) session.load(ChannelEntity.class, new Integer(1));
        System.out.println(channel1.getLabel());
   
        session.getTransaction().commit();
        session.close();
   
        Session anotherSession = sessionFactoryImpl.openSession();
        anotherSession.beginTransaction();
   
        // Here I put a breakpoint and I update the value directly on database.
   
        channel1 = (ChannelEntity) anotherSession.load(ChannelEntity.class, new Integer(1));
        System.out.println(channel1.getLabel()); // Here I print the cached value, not the new database value. Good!
   
        anotherSession.getTransaction().commit();
        anotherSession.close();
    }


But it's not the real context. On my service layer, I don't manipulate directly the transaction, I used the @Transactional Spring annotation.
Here is a more realistic test:

Code:
    private static void testGetChannelFromCache1(BeanFactory factory) throws Exception {
        ChannelService service = (ChannelService) factory.getBean("channelServiceImpl");
        ChannelEntity entity1 = service.getChannelByCode(ChannelCode.ARTE);
        if(entity1 != null) {
            System.out.println(entity1.getLabel());
        }
   
        // Here I put a breakpoint and I update the value directly on database.
   
        ChannelEntity entity2 = service.getChannelByCode(ChannelCode.ARTE);
        if(entity2 != null) {
            System.out.println(entity2.getLabel()); // Here I print the new database value, not the cached value. Not good...
        }
    }


Here is the ChannelService:
Code:
    @Service
    @Transactional(rollbackFor = Exception.class)
    public class ChannelServiceImpl implements ChannelService {
   
        @Log
        private Logger logger;
   
        @Inject
        private ChannelDao channelDao;
   
        @Override
        @Transactional(readOnly = true)
        public ChannelEntity getChannelByCode(final ChannelCode code) throws Exception {
           if(code == null) {
               logger.debug("Cannot find Channel from null code.");
               return null;
           }
           return channelDao.getByCode(code);
        }
    }


Now, my configuration...


Dependencies:
Code:
    <!-- Hibernate -->
    <dependency>
       <groupId>org.hibernate</groupId>
       <artifactId>hibernate-entitymanager</artifactId>
    </dependency>
   
    <!-- Ehcache -->
    <dependency>
       <groupId>net.sf.ehcache</groupId>
       <artifactId>ehcache-core</artifactId>
    </dependency>
    <dependency>
       <groupId>org.hibernate</groupId>
       <artifactId>hibernate-ehcache</artifactId>
    </dependency>


Hibernate configuration:
Code:
    hibernate.cache.region.factory_class=org.hibernate.cache.ehcache.SingletonEhCacheRegionFactory
    hibernate.cache.use_second_level_cache=true
    hibernate.cache.use_query_cache=true
    hibernate.cache.generate_statistics=true
    net.sf.ehcache.configurationResourceName=/config/ehcache/ehcache.xml


EHCache configuration:
Code:
    <cache name="Channel"
           maxEntriesLocalHeap="10000"
           eternal="true"
           overflowToDisk="false">


And I use Spring 4.0.3.RELEASE, Hibernate 4.3.4.Final and EHCache 2.6.8.


To be more accurate, it seems that the @Cache Hibernate annotation work, but not completely...
In fact, I put several breakpoints on the Hibernate source code and I noted that Hibernate put the ChannelEntity on the cache and after my second call to the ChannelService do a get on the cache and retrieve the channel entity!
BUT..., Hibernate still execute the following database request and retrieve the database value. Really strange!

select this_.ChannelId as ChannelI1_3_0_, this_.Code as Code2_3_0_, this_.Label as Label3_3_0_ from Channel this_ where this_.Code=?


Anyone has an idea about this strange behaviour??

Thanks a lot for you help!


Top
 Profile  
 
 Post subject: Re: Cache ignored, Spring 4 @Transactional, Hibernate 4, ehcache
PostPosted: Sat Apr 19, 2014 8:23 pm 
Newbie

Joined: Sat Apr 19, 2014 4:04 pm
Posts: 2
I get a response here => http://stackoverflow.com/questions/23174107/cache-ignored-using-spring-4-transactional-hibernate-4-ehcache


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 2 posts ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.