2013-03-08 13 views
7

Wir haben ein umfangreiches Entitätsmodell mit mehr als 100 Entitätsklassen. Alle Entitätsklassen sind Unterklassen von Superclasses einer einzelnen Entität. Der freigegebene Cache-Modus wurde auf ALL eingestellt.Dedizierter Cache-Bereich für Entitätsunterklassen?

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

} 

Ein Beispiel Unterklasse:

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

Wir möchten alle Objekte in der 2. Ebene Cache zwischenzuspeichern. Das Problem ist, dass nur 1 Cache-Bereich für alle Entitäten erstellt wird; genannt LongIdEntity.

Debugging zeigt Hibernate hat finden Sie alle Entitätsklassen, aber weist ihnen trotzdem die gleiche Region zu. Da bei SessionFactoryImpl: 339:

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

In unserem Fall dem Aufruf von model.getRootClass() immer nachgeben "LongIdEntity".

Ich nehme an, dass dies tatsächlich alle Entitäten zwischenspeichern würde, aber ohne jegliche Kontrolle der Räumung. Einige Klassen sind sehr häufig und schreibgeschützt. Also wollen wir sie in Erinnerung behalten. Einige werden normalerweise in einer bestimmten Zeitspanne verwendet, usw. Wenn Sie alles in denselben Cache schreiben, wird alles ungültig.

Die Angabe der Region in der Annotation hat keine Auswirkung. Zum Beispiel:

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

Das Seltsame ist, dass nur gemeinsame Cache-Modus ALL nimmt die Entitätsklassen auf. In jedem anderen Modus sind keine Entitäten - auch wenn sie mit @Cache und/oder @Cacheable gekennzeichnet sind. Vielleicht ist das ein Hinweis?

Jemand hat eine Idee, wie ich bestimmten Entitätsklassen spezifische Regionen zuweisen kann?

TIA :-)

persistence.xml ist elementar:

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

Die Sitzung Fabrik ist die klassische Art und Weise hergestellt:

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

Die Umgebung

  • JDK6
  • Linux x64
  • Hibernate 4.1.10
  • Frühling 3.2.1

UPDATE: Verwenden Sie @ MappedSuperclass

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

Es wird kein Ding entweder ändern.

+0

Können Sie überprüfen, ob [diese Frage] (http://stackoverflow.com/questions/4452242/specifying-global-ehcache-capacity) das gleiche Problem wie die Sie mit nicht ansprechen? – mindas

+0

Ich versuche, das Gegenteil wirklich zu bekommen. Er versucht, einen großen Cache zu haben, und ich versuche, einen Cache für jede Entität zu haben. Oder überschreiben Sie dieses Verhalten mit @Cache (region = ....). Früher hat es früher so funktioniert, heute wird es ignoriert. –

Antwort

7

Ruhezustand zwischenspeichert die gesamte Hierarchie Einheit in einer Region explizit. Es gibt keine Kontrolle darüber. Es ist die einzige Möglichkeit, die im Cache gespeicherte Auflösung von polymorphen Suchvorgängen korrekt zu behandeln. Andere Anbieter (glaube ich) erlauben eine gewisse Kontrolle darüber, wo/wie jede Unterklasse zwischengespeichert wird (zumindest denke ich, basierend auf den von JPA bereitgestellten Optionen).

+0

Nicht wahr. Ich habe das in der Vergangenheit getan. Ich hatte den Vorschlag, eine andere Vererbungsstrategie zu versuchen. Aber ich sehe nicht, was das mit Caching wirklich zu tun hat. –

+6

Ich bin der führende Entwickler von Hibernate. Ich versichere Ihnen, es speichert eine gesamte abgebildete Hierarchie in einer einzigen Region. Und getan hat so jeder, da sie hatte Caching hat;) –

+0

Blick auf diese https://forum.hibernate.org/viewtopic.php?f=1&t=1025577 :-) –

1

Ich habe dieses Problem hatte, und die Suche nach Internet Ich habe in diesem Thread Stackoverflow endet. Es ist wirklich lehrreich für mich, weil ich das gleiche Problem habe, das der eine in dieser Frage erklärt hat. Das Lesen der Diskussion zwischen Steve Ebersole und Jan Goyvaerts spricht mich zur Lösung meines Falles an. Speziell der Link von einem von ihnen zu Hibernate forum. bei der Erzeugung von verschiedenen gecached Regionen für verschiedene Kinder eines Elternklasse

die Empfehlungen des Forum Testen (auch drei Jahre nach dieser Frage bestanden hat, dann wohl etwas geändert hat) ich Erfolg habe.

In meinem Fall verwendete die Lösung @MappedSuperclassEntfernen@Inheritance(strategy = InheritanceType.JOINED). In diesem Fall kann ich die richtigen Treffer in den richtigen Bereichen sehen.

Als Referenz mein Code ist ähnlich wie:

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


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

Jetzt im Protokoll kann ich sehen:

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

Statt:

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

Natürlich ändert Diese Anmerkungen haben ein anderes Verhalten als die in der Frage verwendete und ist in einigen Fällen nicht die gewünschte. Aber trotzdem denke ich es lohnt sich, diesen Kommentar hier als Nachschlagewerk zu geben. Vielleicht kann andere Person helfen.

+0

Sind Sie sicher, dass die '@Inheritance (strategie = InheritanceType.TABLE_PER_CLASS)' wirklich benötigt wird? Die @MappedSuperclass benötigt nicht die Annotation "@ Vererbung". – Thierry

+0

Sie haben Recht, es ist aus diesem Beispiel. Ich benutze diesen Code, um zu vermeiden, eine Tabelle für eine abstrakte Zwischenklasse zu erstellen, weil ich vergessen habe, auch '@ MappedSuperclass' zu diesen Zwischenklassen hinzuzufügen. Ich repariere es auch in meinem Code und ich aktualisiere diese Antwort.Die Lösung besteht nicht darin, '@Inheritance (strategie = InheritanceType.TABLE_PER_CLASS)' zu setzen, sondern die '@Inheritance (strategie = InheritanceType.JOINED)' zu entfernen – JorgeHortelano