Dedicated cache region for entity subclasses?

爱⌒轻易说出口 提交于 2019-12-05 20:41:58

问题


We have an extensive entity model with 100+ entity classes. All the entity classes are subclasses of a single entity superclasses. The shared cache mode has been set to 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...

}

An example subclass:

@Entity
@Table(name = "cars")
public class Car extends LongIdEntity { ... }

We'd like to cache all entities in the 2nd level cache. The problem is that only 1 cache region is made for all the entities; named LongIdEntity.

Debugging shows Hibernate did find all the entity classes, but assigns them the same region anyway. Because at SessionFactoryImpl:339 :

String cacheRegionName = cacheRegionPrefix + model.getRootClass().getCacheRegionName();

In our case, the call to model.getRootClass() will always yield "LongIdEntity".

I presume this would indeed cache all the entities, but without any control of eviction. Some classes are very frequent and read-only. So we want to keep them pinned into memory. Some are typically used in a certain time span, etc... Cramming it all into the same cache invalidates it all.

Specifying the region in the annotation has no effect. For example:

@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE,region = "cars")
@Entity
@Table(name = "cars")
public class Car extends LongIdEntity { ... }

The weird thing is that only shared cache mode ALL picks up the entity classes. In any other mode no entities are - even when annotated with @Cache and/or @Cacheable. Maybe this is an indication ?

Somebody has an idea how I can assign specific entity classes specific regions ?

TIA :-)

persistence.xml is elementary:

<?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>

The session factory is made the classic way:

  <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>

The environment

  • JDK6
  • Linux x64
  • Hibernate 4.1.10
  • Spring 3.2.1

UPDATE: Use @MappedSuperclass

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

Does not change a thing either.


回答1:


Hibernate caches the entire entity hierarchy in one region explicitly. There is no control over this. Its the only way to properly handled cached resolution of polymorphic lookups. Other providers (I think) do allow some control over where/how each subclass is cached (at least thats my guess based on the options provided by JPA).




回答2:


I have had this issue, and searching for internet I have ending in this Stackoverflow thread. It is really instructive to me due to I have the same issue that the one explained in this question. Reading the discussion between Steve Ebersole and Jan Goyvaerts address me to the solution of my case. Specially the link provided by one of them to Hibernate forum.

Testing the recommendations of the forum (also has passed three years from this question, then probably something has changed) I have success in generating different cached regions for different children of a parent class.

In my case, the solution was using @MappedSuperclass removing @Inheritance(strategy = InheritanceType.JOINED). In this case, I can see the correct hits in the correct areas.

For reference, my code is similar to that:

@MappedSuperclass
public abstract class ParentObject implements Serializable {
    ....


@Entity
@Cacheable(true)
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
public class ChildObject extends ParentObject {
    ....

Now in the log I can see:

Cache: com.<...>.ChildObject store hit for com.<...>.ChildObject#52

Instead of:

Cache: com.<...>.ParentObject store hit for com.<...>.ParentObject#52

Of course, changing this annotations has a different behaviour that the one used in the question, and is not the desired one in some cases. But still I think it worth it to let this comment here as future reference. Maybe can help other person.



来源:https://stackoverflow.com/questions/15294394/dedicated-cache-region-for-entity-subclasses

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!