Ehcache copyOnRead behaviour - java

I have following method which returns data from cache.
Customer customer = customerDao.findByName("Carl");
It returns just one Customer object with name="Carl". When I make following change:
customer.setName("Ron");
and then I call the method again
Customer customer = customerDao.findByName("Carl");
It returns null. I dont make any persist or update operations and the cached object is directly changed.
I tried to use copyOnRead attribute in ehcache config but it doesnt help.
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd">
<!-- default configuration -->
<defaultCache maxElementsInMemory="1000000"
eternal="true" overflowToDisk="false" copyOnRead="true" />
</ehcache>
Is there any way how to force ehcache to copy objects from cache?
Thank you

Related

How to config a cache to point to local ehcache instead of inherited one?

I am trying to use a local ehcache created in my project declared through ehcache.xml file and configured through CacheManager, but am unable to do that and can only use the inherited cache.
Is there a way I can use the cache I declare in the local ehcache.xml file? Please help
I want to create a local Ehcache to store my method results.
My cache config file is below
#Configuration
#Component
#EnableAsync
#EnableCaching
#Primary
public class CacheConfig extends cacheProcessor {
#Bean
#Primary
public EhCacheManagerFactoryBean ehCacheCacheManager() {
EhCacheManagerFactoryBean cmfb = new EhCacheManagerFactoryBean();
cmfb.setConfigLocation(new ClassPathResource("ehcache.xml"));
cmfb.setShared(true);
return cmfb;
}
}
It is trying to override the cache config file defined in the project brought in through dependency because I want to point it to a local ehcache.xml with a new cache name.
My local ehcache.xml file looks like this:
<?xml version="1.0" encoding="UTF-8"?>
<ehcache
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://www.ehcache.org/ehcache.xsd"
name="timePass"
updateCheck="false"
monitoring="autodetect"
dynamicConfig="true">
<diskStore path="java.io.tmpdir" />
<cache name="newCache"
maxEntriesLocalHeap="10000"
maxEntriesLocalDisk="1000"
eternal="false"
diskSpoolBufferSizeMB="20"
memoryStoreEvictionPolicy="LFU"
transactionalMode="off">
<persistence strategy="localTempSwap" />
</cache>
The application class file has a component scan annotation to the inherited projects as well.
My caching service looks like this:
#Component
#Service
public class cacheableService {
#Cacheable(cacheNames = "newCache")
public Collection<ObjectDTO> getAllData(){
return a new list logic
}
}
I am receiving an error, that it cannot find the cache name I have mentioned in the Cacheable annotation, which is the one I declare in the local XML file. And when I use a cache name i.e. in declared in the inherited project ehcache.xml file, it finds the cache.
I have already set the following properties in the application.yml file
spring.cache.ehcache.config.classpath = ehcache.xml
spring.main.allow-bean-definition-overriding = true

EhCache in distributed mode

We are trying to use EhCache as a distributed cache in our application.
EhCache instance are embedded in our server and we used a terracota cluster.
All our server (and ehcache) instances successfully connect to this tc.
We successfully inserts, update and get into each of our caches.
But we cannot iterates over any cache.
Maybe we have configured our caches in the wrong way, but it seems that the iterator methods are not yet implemented (in org.ehcache.clustered.client.internal.store.ClusteredStore):
#Override
public Iterator<Cache.Entry<K, ValueHolder<V>>> iterator() {
// TODO: Make appropriate ServerStoreProxy call
throw new UnsupportedOperationException("Implement me");
}
Our cache configuration looks like the following:
<service>
<tc:cluster>
<tc:connection url="terracotta://10.23.69.20:9510/clustered"/>
<tc:server-side-config auto-create="true">
<tc:default-resource from="default-resource"/>
</tc:server-side-config>
</tc:cluster>
</service>
<cache-template name="CacheTemplate">
<resources>
<tc:clustered-dedicated unit="MB">16</tc:clustered-dedicated>
</resources>
<tc:clustered-store consistency="strong"/>
</cache-template>
<cache alias="CacheDaemon" uses-template="CacheTemplate">
<key-type>java.lang.String</key-type>
<value-type>com.server.cache.DaemonInstance</value-type>
</cache>
<cache alias="CacheProperty" uses-template="CacheTemplate">
<key-type>java.lang.String</key-type>
<value-type>java.lang.String</value-type>
</cache>
I don't found any other way, even getting the key list.
So did we made a mistake in the cache configuration ?
Or is it that the EhCache distributed mode is totally incompatible with this method (and so we won't use EhCache).

How to configure custom ehcaches in Play framework?

Setup:
play framework 2.4.0
built-in ehcache
java
I have followed the manual at https://www.playframework.com/documentation/2.4.0/JavaCache and to separate caches and use different configs (cache sizes, lifetimes etc) I configure in application.conf:
play.cache.bindCaches = ["mycache1-cache","mycache2-cache"]
Then, to configure them, I created the usual ehcache.xml file
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../config/ehcache.xsd" updateCheck="false">
<defaultCache
maxBytesLocalHeap="256000000"
eternal="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
overflowToDisk="false"
maxElementsOnDisk="10000"
diskPersistent="false"
diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LRU"
/>
<cache name="mycache1-cache"
maxBytesLocalHeap="256000000"
eternal="false"
timeToIdleSeconds="86400"
timeToLiveSeconds="86400"
overflowToDisk="true"
maxElementsOnDisk="1000000"
diskPersistent="true"
diskExpiryThreadIntervalSeconds="1200"
memoryStoreEvictionPolicy="LRU"
/>
</ehcache>
It works when I only keep the defaultCache, but as soon as I add the custom cache, play throws with:
ProvisionException: Unable to provision, see the following errors: 1)
Error in custom provider, net.sf.ehcache.ObjectExistsException: Cache
mycache1-cache already exists
However, if I only define the cache in ehcache.xml but not in application.conf, play does not know about it and throws.
I have also faced the same issue a month ago and tried to search over internet and below solution that works for me. You can also try to do same.
/** Bind named caches using configuration in ehcache.xml. Define a named cache in ehcache.xml and Ehcache will automatically instantiate the cache at runtime. However,this cache is unknown to the Play cache plugin and is not accessible using {#code #NamedCache}. You must bind a reference to the named cache using {#link CacheModule#bindCustomCache(String)}. Do not add the named cache to {#code play.cache.bindCaches} in configuration. Caches bound in this manner are programmatically added by the Play cache plugin at runtime. The cache plugin will always copy settings from the default cache, limiting the usefulness of named caches. **/
public class CacheModule extends AbstractModule {
#Override
protected void configure() {
bindCustomCache("tenants");
bindCustomCache("user-agent");
bindCustomCache("geo-ip");
bindCustomCache("full-contact");
}
/**
* Bind a named cache that is defined in ehcache.xml.
*
* #param name The name of the cache.
*/
private void bindCustomCache(String name) {
bind(CacheApi.class)
.annotatedWith(new NamedCacheImpl(name))
.toProvider(new Provider<CacheApi>() {
#Inject
CacheManager cacheManager;
#Override
public CacheApi get() {
Cache cache = cacheManager.getCache(name);
if (cache == null) {
throw new RuntimeException("Cache named '" + name + "' must be defined in ehcache.xml");
}
return new DefaultCacheApi(new EhCacheApi(cache));
}
})
.asEagerSingleton();
}
}
I create my named caches in ehcache.xml and just have to add a one line bindCustomCache() to the configure method.
You will also need to set play.cache.createBoundCaches = false in application.conf.

Hibernate 2nd level cache without ehcache.xml

I am trying to configure Ehcache as a hibernate 2nd-level cache, and so far all the examples I've found instruct you to create an ehcache.xml file in the classpath like:
<ehcache updateCheck="false">
<diskStore path="java.io.tmpdir" />
<defaultCache maxElementsInMemory="10000" eternal="false"
statistics="true" timeToIdleSeconds="120" timeToLiveSeconds="120"
overflowToDisk="true" diskPersistent="false"
diskExpiryThreadIntervalSeconds="120" memoryStoreEvictionPolicy="LRU" />
<cache name="com.yourcompany.CachedEntity" eternal="true" maxElementsInMemory="1000" />
</ehcache>
And then configure Hibernate as follows:
<property name="hibernate.cache.region.factory_class" value="org.hibernate.cache.ehcache.SingletonEhCacheRegionFactory"/>
<property name="net.sf.ehcache.configurationResourceName" value="/ehcache.xml" />
<property name="hibernate.cache.use_query_cache" value="true" />
<property name="hibernate.cache.use_second_level_cache" value="true" />
In my workplace we are encouraged to use java config wherever possible and avoid XML config files. I'd appreciate any pointers on how this can be achieved.
The stackoverflow question using ehcache in spring 4 without xml mentioned by learningJava shows how to configure an ehcache CacheManager in java but you still need a way to tell hibernate that it should use your java configured CacheManager.
A possible way to this would be to configure a custom ehcache region factory via the hibernate.cache.region.factory_class property. If you look at the implementation of SingletonEhCacheRegionFactory you'll see that it will be quite easy to swap in your own CacheManager.
I suspect that the mapping between the java configuration and the xml configuration of a cache is quite straightforward, but if ehcache performs some 'magic stuff' behind the scenes when it parses the xml configuration, the job of getting your java configuration right might be a bit trickier.
I also could not find sample code for this problem so I thought that I would share my solution. #Pieter 's answer set me on the right track and you need to implement your own EhCacheRegionFactory class so that you can provide custom java Configuration objects. It appears that the stock library only supports xml. Here's what my solution looks like:
public class CustomEhCacheRegionFactory extends EhCacheRegionFactory{
private static final EhCacheMessageLogger LOG = Logger.getMessageLogger(
EhCacheMessageLogger.class,
CustomCacheRegionFactory.class.getName()
);
#Override
public void start(Settings settings, Properties properties) throws CacheException {
this.settings = settings;
if ( manager != null ) {
LOG.attemptToRestartAlreadyStartedEhCacheProvider();
return;
}
try {
final Configuration configuration = new Configuration();
configuration.addCache( getEntityCacheConfiguration() );
manager = new CacheManager( configuration );
mbeanRegistrationHelper.registerMBean( manager, properties );
}
catch (net.sf.ehcache.CacheException e) {
//handle
}
}
/**
* Create the basic second level cache configuration
* #return
*/
private CacheConfiguration getEntityCacheConfiguration()
{
CacheConfiguration config = new CacheConfiguration("entity", 50000);
config.setTimeToIdleSeconds(86400);
config.setTimeToLiveSeconds(86400);
return config;
}
}

Hibernate throws queries even on cache hits

I'm not sure if it's a real problem or it's only a matter of configuration but I can see on my log console how hibernate hits (or at least throws the select query) even on cache hits.
I've checked the cache is properly working on Ehcache monitor and it registers 100% of hits for a certain request. But I always see the queries in the log.
All entities are anotated as shown:
#Entity
#Cacheable
#Cache(usage = READ_WRITE)
#Table(name = "city")
//#NamedQuery(name = "city.findById", query = "from City where ID = :id")
public class City extends Audit implements Serializable {
My ehcache.xml
<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd"
dynamicConfig="true" monitoring="autodetect">
<!-- Location of persistent caches on disk -->
<diskStore path="java.io.tmpdir/MxlServiceLayer" />
<cacheManagerPeerListenerFactory
class="org.terracotta.ehcachedx.monitor.probe.ProbePeerListenerFactory"
properties="monitorAddress=localhost, monitorPort=9889, memoryMeasurement=true" />
<defaultCache eternal="false" maxElementsInMemory="1000"
overflowToDisk="false" diskPersistent="false" timeToIdleSeconds="0"
timeToLiveSeconds="600" memoryStoreEvictionPolicy="LRU" statistics="true" />
<cache name="authToken" eternal="false" maxElementsInMemory="100"
overflowToDisk="false" diskPersistent="true" timeToIdleSeconds="0"
timeToLiveSeconds="31536000" memoryStoreEvictionPolicy="LRU"
statistics="true" />
</ehcache>
And what I see in my over and over again...
Hibernate: select city0_.ID as ID2_, city0_.CREATED as CREATED2_,
city0_.CREATOR as CREATOR2_, city0_.MODIFIED as MODIFIED2_,
city0_.MODIFIER as MODIFIER2_, city0_.NAME as NAME2_, city0_.state_fk
as state7_2_ from city city0_ where State_fk=?
Is hibernate really hitting the DB? Can anyone explain this to me, please?
I'm using:
JPA 2.0 in Spring Data JPA 1.2.0
Ehcache 2.6.0
Spring 3.2.1
What you enabled is the second-level cache. This cache caches the state of the entities, and indexes them by their ID. It's like a Map<ID, EntityState>. This cache is only used if you get the entity by ID:
by calling session.get()
by calling session.load()
by navigating through a XxxToOne association targeting the entity
Your query doesn't fall into this category: it looks for your entity by one of its fields, and not by its ID.
For the rest, Hibernate can't execute arbitrary SQL queries against the cache, and even if it could, the cache only contains a subset of the table, so it has to query the database.
You can however, cache the result of queries as well. You'll need to enable the query cache to do so, and to mark your query as cacheable. You can also cache an association (which seems like the reason for this query: it's looking for all the cities of a given state). You'll have to annotate the association with #Cache.
Read the documentation.

Categories

Resources