【问题标题】:Dedicated cache region for entity subclasses?实体子类的专用缓存区域?
【发布时间】:2017-01-10 18:10:28
【问题描述】:

我们拥有一个包含 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>

环境

  • JDK6
  • Linux x64
  • 休眠 4.1.10
  • 春季 3.2.1

更新:使用@MappedSuperclass

@MappedSuperclass
@Inheritance(strategy = InheritanceType.JOINED)
public abstract class LongIdEntity { ... }

也不会改变任何事情。

【问题讨论】:

  • 您能检查一下this question 是否解决了与您遇到的问题相同的问题吗?
  • 我试图得到相反的结果。他试图拥有一个大缓存,而我试图为每个实体拥有一个缓存。或者用@Cache(region= ....) 覆盖这个行为。早期它曾经是这样工作的,但今天它被忽略了。

标签: hibernate jpa-2.0 ehcache


【解决方案1】:

Hibernate 将整个实体层次结构明确地缓存在一个区域中。对此无法控制。它是正确处理多态查找的缓存解析的唯一方法。其他提供者(我认为)确实允许对每个子类的缓存位置/方式进行一些控制(至少这是我基于 JPA 提供的选项的猜测)。

【讨论】:

  • 不正确。我过去曾这样做过。我曾建议尝试不同的继承策略。但我不明白这与缓存有什么关系。
  • 我是 Hibernate 的首席开发人员。我向您保证,它将整个映射层次结构缓存在单个区域中。自从它有缓存以来就一直这样做;)
  • 使用@MappedSuperclass 不是实体层次结构。一点语义。本质上,在修改后的模型中,LongIdEntity 的每个直接实体子类都是不同的持久层次结构。
  • 使它成为@MappedSuperclass 并没有改变任何事情。很遗憾。所以这可能就像线程的人所暗示的那样 - 与连接继承有关。但是和缓存有什么关系呢?
  • 不,我没有这个计划。
【解决方案2】:

我遇到了这个问题,并且搜索互联网我已经结束了这个 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

当然,更改此注释具有与问题中使用的不同的行为,并且在某些情况下不是所需的行为。但我仍然认为值得在这里发表此评论作为将来的参考。也许可以帮助其他人。

【讨论】:

  • 您确定真的需要@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS) 吗? @MappedSuperclass 不需要 @Inheritance 注释。
  • 你是对的,它不在这个例子中。我使用此代码来避免为某些中间抽象类创建表,因为我忘记将 @MappedSuperclass 也添加到这些中间类中。我也在我的代码中修复了它,并更新了这个答案。解决方法是不要放@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS),而是去掉@Inheritance(strategy = InheritanceType.JOINED)
猜你喜欢
  • 2017-10-03
  • 2023-03-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多