英文:
How to programmatically configure L2 Hibernate caches with ECache?
问题
I can provide a summary of the issue and some possible solutions:
You're facing problems while trying to configure L2 caching with custom settings in Hibernate 6.1.7 within your Spring 6 application using Ehcache 3.10.x. It seems that when you change the CacheConcurrencyStrategy
, you encounter exceptions, and the cache behavior becomes unreliable.
Possible solutions or directions to explore:
-
Review Cache Configuration: Double-check your cache configuration for consistency, including entity annotations, cache names, and concurrency strategies. Ensure that your entity classes and cache settings are aligned.
-
Concurrency Strategy: It appears that changing the
CacheConcurrencyStrategy
leads to issues. Review the documentation for Hibernate and Ehcache to ensure that you're using the correct strategy for your use case. It might be necessary to choose a strategy that matches your entity and usage patterns. -
Debugging: Debug the code to understand why the exceptions occur when changing the concurrency strategy. Investigate which part of the code is causing the class cast exceptions and consider modifying the code accordingly.
-
Consult the Community: Seek help and advice from the Hibernate and Ehcache communities or forums. Others might have encountered similar issues or have insights into the best practices for configuring L2 caching with custom settings.
-
Upgrade: Check if there are newer versions of Hibernate and Ehcache available that might address these issues or provide better documentation and support for custom L2 caching configurations.
Remember to keep backups of your code and configurations before making significant changes, and test any modifications in a controlled environment to avoid potential issues in production.
英文:
I'm trying to configure L2+QueryCache for Hibernate 6.1.7 in my Spring 6 app running Ehcache 3.10.x
In my app, Spring-level caches with method-level @Cacheable
, @CachePut
, @CacheEvict
, etc. work fine. I create the caches and they work as expected.
L2 cache also works correctly, but only if I don't create any L2 caches and let Spring create the default ones (missing_cache_strategy: create
). This is presentig heap-related problems in production because the default cache settings in Ehcache are allowing infinite heap usage.
How do I create L2 caches with my own configs, from code? I want to avoid the xml
Ehcache config at this time, and Ehcache seems to be moving away from it anyway.
This is how I configure Spring-level caches, and it works:
@Configuration
@EnableCaching
public class MyCacheConfig {
@Bean
public CacheManager ehCacheManager() {
CacheManager cacheManager = Caching.getCachingProvider().getCacheManager();
//Create a Spring-level cache
var config = CacheConfigurationBuilder
.newCacheConfigurationBuilder(SomeMethodArg.class, SomeMethodReturnType.class)
.withExpiry(ExpiryPolicyBuilder.timeToIdleExpiration(Duration.ofMinutes(30))
.build();
cacheManager.createCache("my_spr_cache", Eh107Configuration.fromEhcacheCacheConfiguration(config));
return cacheManager;
}
}
Following the Ehcache docs and other sources, I was able to create L2 caches in a similar manner by adding another cache to the bean above:
//Create a L2 cache
var config = CacheConfigurationBuilder
.newCacheConfigurationBuilder(CacheKeyImplementation.class, AbstractReadWriteAccess.Item.class)
.withExpiry(ExpiryPolicyBuilder.timeToIdleExpiration(Duration.ofMinutes(30))
.build();
//L2 cache name should be the fully qualified name of the Entity
cacheManager.createCache("com.mydomain.model.MyClass", Eh107Configuration.fromEhcacheCacheConfiguration(config));
And of course, the MyClass Entity is annotated with:
@jakarta.persistence.Cacheable
@org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.READ_WRITE) //Note that some other classes instead use NONSTRICT_READ_WRITE
Now the cache I made is correctly created at runtime and Ehcache doesn't build a default one. I can confirm this from the startup logs - manually created caches are logged significantly earlier on.
Now the issue: this method is unreliable. Firstly, it seems that changing the ConcurrencyStrategy
breaks the cache creation code, for example, switching to NONSTRICT_READ_WRITE
on the entity will cause Exceptions:
Exception in thread "(3/16)" java.lang.ClassCastException: Invalid value type,
expected: org.hibernate.cache.spi.support.AbstractReadWriteAccess$Item
but was : org.hibernate.cache.spi.entry.StandardCacheEntryImpl
The first attempt I made was obviously following the exception literally and changing the value class to StandardCacheEntryImpl
. This just causes even more erratic behavior, with the cache behaving fine at low usage but failing when consistent load is applied:
Caused by: java.lang.ClassCastException: Invalid value type,
expected : org.hibernate.cache.spi.support.AbstractReadWriteAccess$Item
but was : org.hibernate.cache.spi.support.AbstractReadWriteAccess$SoftLockImpl
If I switch those two classes back and forth, I get the same exception but reversed.
This leads me to believe that I'm using the wrong approach entirely. I can't find any modern and updated question on this, could someone kindly point me in the right direction?
If it can be useful, this is the relevant config in my application.yml
:
# [More settings here...]
jpa:
# [More settings here...]
properties:
jakarta:
persistence:
sharedCache:
#required - enable selective caching mode - only entities with @Cacheable annotation will use L2 cache.
mode: ENABLE_SELECTIVE
hibernate:
cache:
use_second_level_cache: true
use_query_cache: true
region:
factory_class: org.hibernate.cache.jcache.JCacheRegionFactory
jakarta:
cache:
missing_cache_strategy: create
答案1
得分: 0
For cache keys, Hibernate
可能会使用三种不同的实现(请检查 org.hibernate.cache.spi.CacheKeysFactory
接口以及其 createCollectionKey
、createEntityKey
和 createNaturalIdKey
方法),此外,Hibernate
允许通过 hibernate.cache.keys_factory
设置来覆盖默认的 CacheKeysFactory
,所以从技术上讲,您无法猜测特定缓存区域将使用哪种缓存键实现,而且缓存区域可能包含不同的数据,因此 Object.class
也是缓存键实现的有效定义。
对于缓存值的实现也可能不同:
- 对于自然ID缓存,
Hibernate
在那里存储实体标识符 - 对于其他缓存,可以是
Map
、StandardCacheEntryImpl
或org.hibernate.cache.spi.support.AbstractReadWriteAccess.Lockable
的实现
所以,对于缓存值,Object.class
也是唯一有效的定义。
英文:
For cache keys Hibernate
may potentially use three different implementations (please check org.hibernate.cache.spi.CacheKeysFactory
interface and it's createCollectionKey
, createEntityKey
and createNaturalIdKey
methods), moreover, Hibernate
, allows to override default CacheKeysFactory
via hibernate.cache.keys_factory
setting, so, technically you have no chance to guess what cache key implementation will be used for particular cache region, moreover cache regions may contain different data, so, Object.class
is a valid definition of cache key implementation.
In case of cache values implementations may also differ:
- for natural id cache
Hibernate
stores entity identifiers there - for other caches that can be either
Map
orStandardCacheEntryImpl
or implementation oforg.hibernate.cache.spi.support.AbstractReadWriteAccess.Lockable
so, for cache values Object.class
is the only valid definition as well.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论