I'm setting up a cluster environment and I want my JPA's second level cache to be replicated throughout the cluster's nodes. I'm using eclipselink as JPA provider and redis for cache management.
Asked
Active
Viewed 783 times
2
-
[This answer](https://stackoverflow.com/a/35627313/4754790) might be helpful when considering both correctness and performance aspects of remote L2 caches. It covers the way how Hibernate interacts with the L2 cache, I'm not sure how it works in EclipseLink (I assume there are lots of similarities). – Dragan Bozanovic Sep 13 '19 at 12:07
-
It's an interesting idea. Am I correct in my guess that your intention is to use it for a sort of L2 cache that would be shared across the nodes of a cluster? – Captain Sep 15 '19 at 09:42
-
@Captain yes. like hibernate-redis i want eclipselink L2 cache to be shared a across all nodes in cluster using redis. – Bharat Gadde Sep 16 '19 at 05:35
1 Answers
1
There is no official or community project that support it.
However, you can implement your own CacheInterceptor.
Eg.
import org.eclipse.persistence.descriptors.ClassDescriptor;
import org.eclipse.persistence.internal.identitymaps.CacheKey;
import org.eclipse.persistence.internal.identitymaps.IdentityMap;
import org.eclipse.persistence.internal.sessions.AbstractSession;
import org.eclipse.persistence.sessions.interceptors.CacheInterceptor;
import org.eclipse.persistence.sessions.interceptors.CacheKeyInterceptor;
import java.util.Map;
public class MyRedisCacheInterceptor extends CacheInterceptor {
private final MyCacheProvider cacheSupport;
private final String cacheName;
public DefaultCacheInterceptor(IdentityMap targetIdentityMap, AbstractSession interceptedSession,
String cacheName, DefaultCacheSupport cacheSupport) {
super(targetIdentityMap, interceptedSession);
this.cacheSupport = cacheSupport;
this.cacheName = cacheName;
}
@Override
public Object clone() {
return null;
}
@Override
protected CacheKeyInterceptor createCacheKeyInterceptor(CacheKey wrappedCacheKey) {
final long longKey = (long) wrappedCacheKey.getKey();
CacheKeyInterceptor newKey = new CacheKeyInterceptor(wrappedCacheKey) {
@Override
public Object getObject() {
return cacheSupport.getOrCreateCache(cacheName).get(longKey);
}
@Override
public void setObject(Object object) {
cacheSupport.getOrCreateCache(cacheName).put(longKey, object);
}
};
return newKey;
}
@Override
public boolean containsKey(Object primaryKey) {
return cacheSupport.getOrCreateCache(cacheName).containsKey(primaryKey);
}
@Override
public Map<Object, Object> getAllFromIdentityMapWithEntityPK(Object[] pkList, ClassDescriptor descriptor, AbstractSession session) {
return null;
}
@Override
public Map<Object, CacheKey> getAllCacheKeysFromIdentityMapWithEntityPK(Object[] pkList, ClassDescriptor descriptor, AbstractSession session) {
return null;
}
@Override
public void release() {
}
}
You can take a look to this project that uses Apache Ignite, replace it with Redis and try. sample project
Cache Interceptor Impl: Sample cache interceptor impl
Ignite Cache Interceptor: Sample Ignite cache interceptor project
Other sample project with Hazelcast: Sample Hazelcast cache interceptor project
In short, If you need to use Redis as a second level cache you need to implement your own customization or maybe Hibernate is your best choice. It has a redisson-hibernate cache provider that you can plug (redisson-hibernate).
Regards,

Ariel Carrera
- 5,113
- 25
- 36
-
Thanks. It worked but few changes were needed as while retrieving from DB for the first time and putting in cache the `setObject` of `CacheKeyInterceptor` will be passed an empty object of your bean i.e no attribute of this object will be set by this time. so immediately putting it in redis will put this empty object in cache which will be of no use. So for now, as a work around i put the bean in redis in `updateAccess` which will be called after the object's attributes are properly set. – Bharat Gadde Sep 27 '19 at 19:59