Creating an implementaion of L2 cache for hibernate based on Redis

Greetings,

My goal is to create L2 cache based on Redis without JTA support. I apologize if this question was asked previously, though I didn’t find any on hibernate forum.

To begin with there is almost no guidelines how or where to start. I analyzed dozens of articles, github repositories and read 3 books on Redis itself about caching and it’s strategies. In the end I’ve started to read through hibernate cache SPI hibernate-orm/hibernate-core/src/main/java/org/hibernate/cache/spi at main · hibernate/hibernate-orm · GitHub

There are number of access interfaces : CollectionDataAccess, EntityDataAccess, NaturalIdDataAccess, CachedDomainDataAccess. These interfaces are meant to be a “Contract for managing transactional and concurrent access”. Under the hood hibernate implementation uses StorageAccess interface to access L2 cache, which is also working with transactional access and non-transactional for eviction.

First question. Am I right to understand that CollectionDataAccess, EntityDataAccess, NaturalIdDataAccess, CachedDomainDataAccess are responsible for “application” wide transactions (has nothing to do with the L2 Cache) and StorageAccess is responsible for transactional access to L2 Cache (Redis) itself ? Can I rely on implementations provided by hibernate for CollectionDataAccess, EntityDataAccess, NaturalIdDataAccess, CachedDomainDataAccess ?

We have different AccessType variants hibernate-orm/hibernate-core/src/main/java/org/hibernate/cache/spi/access/AccessType.java at main · hibernate/hibernate-orm · GitHub

Second question, probably a newbie one. The doc is clear about NONSTRICT_READ_WRITE and READ_ONLY. Though it forces engineer to question what are “soft” and “hard” locks in terms of TRANSACTIONAL and READ_WRITE access. Assuming that I have multiple instances of an “application” which use L2 Cache(Redis). Am I right that “soft” lock is one which resides inside L2 Cache (Redis) and “hard” lock is a kind of JTA feature of enterprise grade server like WildFly ?

Thank you !

Regards,
rixterd2

The cache does not have to be transactional and you don’t need to support JTA if you want to write a customer cache integration, though you should probably rather use the Redis JCache implementation and stick to Hibernate ORMs JCache integration module or use the Redisson Hibernate ORM integration.

1 Like

Hello, Christian !

Thank you for the reply !

Unfortunately hibernate uses javax for JCache module and we are moving away to jakarta 10. By the way are there any plans/roadmaps on jakarta migration for this module ?

I’m surprised that we can avoid synchronization on cache with hibernate. Can you please share your thoughts on that ?

Let’s for example take AccessType.READ_WRITE and multiple “services” sharing the same L2 cache. I thought that it will require some kind locking inside L2 cache just to ensure that we always have consistent state of shared entities. Obviously I’m mistaken if you’re saying that cache does not have to be transactional. How does hibernate preserve data consistency when using shared ( among different application instances ) L2 cache then ?

How do I avoid : modify (instance 1) → get & cache (instance 2 ) → cache invalidation (instance 1) ? Data consistency is broken in such scenarios.

P.S> My colleague has found implementation of a lock for READ_WRITE access inside hibernate hibernate-orm/hibernate-core/src/main/java/org/hibernate/cache/spi/support/AbstractReadWriteAccess.java at main · hibernate/hibernate-orm · GitHub
I thought it should be on a cache provider side :slight_smile:

Regards,
rixterd2

Unfortunately hibernate uses javax for JCache module and we are moving away to jakarta 10. By the way are there any plans/roadmaps on jakarta migration for this module ?

JCache is not part of Jave/Jakarta EE and never transitioned to the jakarta namespace.

Let’s for example take AccessType.READ_WRITE and multiple “services” sharing the same L2 cache. I thought that it will require some kind locking inside L2 cache just to ensure that we always have consistent state of shared entities. Obviously I’m mistaken if you’re saying that cache does not have to be transactional. How does hibernate preserve data consistency when using shared ( among different application instances ) L2 cache then ?

How do I avoid : modify (instance 1) → get & cache (instance 2 ) → cache invalidation (instance 1) ? Data consistency is broken in such scenarios.

This is usually avoided by creating a sort of “tombstone” entry for a particular cache key, which has a certain TTL, though I am no expert in this area. I guess hibernate-orm/hibernate-core/src/main/java/org/hibernate/cache/spi/support/AbstractReadWriteAccess.java at main · hibernate/hibernate-orm · GitHub that you found is exactly about that.

I thought it should be on a cache provider side :slight_smile:

Since most cache providers don’t support participating in a transaction, Hibernate ORM implements this through such means.

1 Like