First Level Cache
Persistence Context for each Transaction have first level cache
Second Level Cache
Across multiple transactions
Store the common information for all the users of an application
Second level cache for Service method (int -> int)
implementation 'org.springframework.boot:spring-boot-starter-cache'
implementation 'javax.cache:cache-api'
implementation 'org.hibernate:hibernate-jcache'
implementation 'org.ehcache:ehcache'
@Service
public class WorkerService {
private final Random random = new Random();
@Cacheable(value = "worker1", key = "#bound")
public int getFirstWork(int bound) {
return random.nextInt(bound);
}
@Cacheable(value = "worker2", key = "#bound")
public int getSecondWork(int bound) {
return random.nextInt(bound);
}
}
XML Configuration for Second level cache for Service method
spring.cache.jcache.config=classpath:ehcache.xml
<config
xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
xmlns='http://www.ehcache.org/v3'
xsi:schemaLocation="
http://www.ehcache.org/v3
http://www.ehcache.org/schema/ehcache-core-3.7.xsd">
<!-- Persistent cache directory -->
<persistence directory="spring-boot-ehcache/cache" />
<!-- Default cache template -->
<cache-template name="default">
<expiry>
<ttl unit="seconds">30</ttl>
</expiry>
<listeners>
<listener>
<class>com.example.demo6.config.CacheLogger</class>
<event-firing-mode>ASYNCHRONOUS</event-firing-mode>
<event-ordering-mode>UNORDERED</event-ordering-mode>
<events-to-fire-on>CREATED</events-to-fire-on>
<events-to-fire-on>EXPIRED</events-to-fire-on>
<events-to-fire-on>EVICTED</events-to-fire-on>
</listener>
</listeners>
<resources>
<heap>1000</heap>
<offheap unit="MB">10</offheap>
<disk persistent="true" unit="MB">20</disk>
</resources>
</cache-template>
<cache alias="getFirstWork" uses-template="default">
<key-type>java.lang.Integer</key-type>
<value-type>java.lang.Integer</value-type>
</cache>
<cache alias="getSecondWork" uses-template="default">
<key-type>java.lang.Integer</key-type>
<value-type>java.lang.Integer</value-type>
</cache>
</config>
public class CacheLogger implements CacheEventListener<Object, Object> {
private final Logger LOG = LoggerFactory.getLogger(CacheLogger.class);
@Override
public void onEvent(CacheEvent<?, ?> cacheEvent) {
LOG.info("Key: {} | EventType: {} | Old value: {} | New value: {}",
cacheEvent.getKey(), cacheEvent.getType(), cacheEvent.getOldValue(),
cacheEvent.getNewValue());
}
}
Java Configuration for Second level cache for Service method
@Configuration
@EnableCaching
public class EhcacheConfig {
private static final Factory<? extends CacheEntryEventFilter<Integer, Integer>> NO_FILTER = null;
private static final boolean IS_OLD_VALUE_REQUIRED = false;
private static final boolean IS_SYNCHRONOUS = true;
private final javax.cache.configuration.Configuration<Integer, Integer> jcacheConfiguration =
Eh107Configuration.fromEhcacheCacheConfiguration(
CacheConfigurationBuilder
.newCacheConfigurationBuilder(Integer.class, Integer.class, ResourcePoolsBuilder.heap(100))
.withExpiry(ExpiryPolicyBuilder.timeToLiveExpiration(Duration.ofMinutes(5)))
.build()
);
CacheEntryListenerConfiguration<Integer, Integer> listenerConfiguration =
new MutableCacheEntryListenerConfiguration<>(
FactoryBuilder.factoryOf(CacheListener.class),
NO_FILTER,
IS_OLD_VALUE_REQUIRED,
IS_SYNCHRONOUS);
@Bean
public JCacheManagerCustomizer cacheManagerCustomizer() {
return cm -> {
createCache(cm, "worker1");
createCache(cm, "worker2");
};
}
private void createCache(CacheManager cm, String cacheName) {
Cache<Integer, Integer> cache = cm.getCache(cacheName);
if (cache == null) {
cm.createCache(cacheName, jcacheConfiguration)
.registerCacheEntryListener(listenerConfiguration);
}
}
}
public class CacheListener implements CacheEntryCreatedListener<Integer, Integer> {
private final Logger log = LoggerFactory.getLogger(this.getClass());
@Override
public void onCreated(final Iterable<CacheEntryEvent<? extends Integer, ? extends Integer>> cacheEntryEvents) {
for (CacheEntryEvent<? extends Integer, ? extends Integer> entryEvent : cacheEntryEvents) {
log.info("Cached key: {}, with value: {}", entryEvent.getKey(), entryEvent.getValue());
}
}
}
Second level cache for Entity
@Entity
// @Cacheable
@org.hibernate.annotations.Cache(region = EhcacheConfig.DB_CACHE, usage = CacheConcurrencyStrategy.READ_ONLY)
public class Course {
// @Configuration
// @EnableCaching
public class EhcacheConfig {
public static final String DB_CACHE = "db_cache";
}
Not working for findAll()
Looks like working for findById()