我们有一个包含100多个实体类的广泛实体模型。所有实体类都是单个实体超类的子类。共享缓存模式已设置为 ALL 。
@Entity
@Inheritance(strategy = InheritanceType.JOINED)
@Table(name = "entities")
public abstract class LongIdEntity {
@Id
@GeneratedValue(strategy = GenerationType.TABLE)
private Long id;
@Version
@Column(name = "OPT_LOCK_VERSION")
private Long lockVersion;
etc...
}
一个示例子类:
@Entity
@Table(name = "cars")
public class Car extends LongIdEntity { ... }
我们想要缓存二级缓存中的所有实体。问题是只为所有实体制作了1个缓存区域;命名为 LongIdEntity 。
调试显示Hibernate 找到所有实体类,但无论如何都要为它们分配相同的区域。因为 SessionFactoryImpl:339 :
String cacheRegionName = cacheRegionPrefix + model.getRootClass().getCacheRegionName();
在我们的例子中,对 model.getRootClass()的调用将始终产生“ LongIdEntity ”。
我认为这确实会缓存所有实体,但没有任何驱逐控制。有些课程非常频繁且只读。所以我们希望将它们固定在内存中。有些通常在某个时间跨度内使用,等等......将它们全部塞进同一个缓存中会使一切无效。
在注释中指定区域无效。例如:
@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE,region = "cars")
@Entity
@Table(name = "cars")
public class Car extends LongIdEntity { ... }
奇怪的是,只有共享缓存模式 ALL 才能获取实体类。在任何其他模式中,没有实体 - 即使使用@Cache和/或@Cacheable进行注释。也许这是一个迹象?
有人知道如何分配特定实体类的特定区域吗?
TIA: - )
persistence.xml 是基本的:
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
<persistence-unit name="cars" transaction-type="RESOURCE_LOCAL">
<shared-cache-mode>ALL</shared-cache-mode>
</persistence-unit>
</persistence>
会话工厂是经典的方式:
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceProviderClass" value="org.hibernate.ejb.HibernatePersistence"/>
<property name="persistenceUnitName" value="optimus"/>
<property name="dataSource" ref="dataSource"/>
<property name="jpaProperties">
<props>
<prop key="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.SingletonEhCacheRegionFactory</prop>
<prop key="hibernate.cache.use_second_level_cache">true</prop>
<prop key="hibernate.cache.use_query_cache">true</prop>
<prop key="hibernate.generate_statistics">true</prop>
<prop key="hibernate.cache.default_cache_concurrency_strategy">NONSTRICT_READ_WRITE</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
<prop key="hibernate.jdbc.batch_size">1000</prop>
<prop key="hibernate.show_sql">false</prop>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQL5InnoDBDialect</prop>
<prop key="hibernate.search.default.directory_provider">filesystem</prop>
<prop key="hibernate.search.default.indexBase">/hibernate-search</prop>
</props>
</property>
</bean>
环境
更新:使用@MappedSuperclass
@MappedSuperclass
@Inheritance(strategy = InheritanceType.JOINED)
public abstract class LongIdEntity { ... }
也不会改变一件事。
答案 0 :(得分:7)
Hibernate显式地将整个实体层次结构缓存在一个区域中。无法控制这一点。它是正确处理多态查找的缓存解析的唯一方法。其他提供程序(我认为)允许对每个子类的缓存位置/方式进行一些控制(至少这是我根据JPA提供的选项进行的猜测)。
答案 1 :(得分:1)
我遇到过这个问题,搜索互联网我已经在这个Stackoverflow线程中结束了。这对我来说真的很有启发,因为我遇到了与本问题中解释的问题相同的问题。阅读Steve Ebersole和Jan Goyvaerts之间的讨论让我了解了我的案例。特别是其中一个提供给Hibernate forum的链接。
测试论坛的建议(从这个问题开始已经过了三年,然后可能已经发生了变化)我成功地为父类的不同子级生成了不同的缓存区域。
就我而言,解决方案是使用@MappedSuperclass
删除 @Inheritance(strategy = InheritanceType.JOINED)
。在这种情况下,我可以在正确的区域看到正确的命中。
作为参考,我的代码类似于:
@MappedSuperclass
public abstract class ParentObject implements Serializable {
....
@Entity
@Cacheable(true)
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
public class ChildObject extends ParentObject {
....
现在在日志中我可以看到:
Cache: com.<...>.ChildObject store hit for com.<...>.ChildObject#52
而不是:
Cache: com.<...>.ParentObject store hit for com.<...>.ParentObject#52
当然,更改此注释的行为与问题中使用的行为不同,在某些情况下不是所需的行为。但我仍然认为值得将此评论作为未来参考。也许可以帮助别人。