2015-06-19 5 views
6

Ich habe ein Problem, bei dem eine Validation Instanz zu einer Collection in einer Step Instanz hinzugefügt wird. Erklärung ist wie folgt:Cache-Inkonsistenz - Entität nicht immer im Cache gespeichert Auflistung

Schritt Klasse:

@Entity 
@Table 
@Cacheable 
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE) 
public class Step extends AbstractEntity implements ValidatableStep { 

    @OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true) 
    @JoinColumn(name = "step_id", nullable = false) 
    @Cache(usage = CacheConcurrencyStrategy.READ_WRITE) 
    private Set<Validation> validations = new HashSet<>(); 

    @Override 
    public void addValidation(Validation validation) { 
     // do some stuff 
     ... 
     // add validation instance to collection 
     getValidations().add(validation); 
    } 

} 

Validation Klasse:

@Entity 
@Table 
@Cacheable 
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE) 
@NoArgsConstructor(access = AccessLevel.PROTECTED) 
public class Validation extends AbstractEntity { 
    //some properties 
} 

Beide Klassen sind Cacheable mit einer READ_WRITE angewendet Strategie. Die unidirektionale Sammlung von Validations wird ebenfalls mit derselben Strategie zwischengespeichert.

Man würde erwarten, wenn eine Lese-Schreib-Transaktion, die addValidation(new Validation('userName')); commits aufruft, die neue Validation in einer nachfolgenden schreibgeschützten Transaktion sichtbar wäre. Das Seltsame ist, dass es manchmal funktioniert und manchmal nicht funktioniert ...

Die erste Transaktion ist immer erfolgreich; Wir sehen, dass die neue Validierung in der Datenbank beibehalten wird und die Versionseigenschaft Step (für optimistisches Sperren) erhöht wird. Aber manchmal, enthält die zweite Lesetransaktion eine Step Instanz mit einem leeren Validation Sammlung ...

Unsere Hibernate Caching Config ist wie folgt:

hibernate.cache.use_second_level_cache = true 
hibernate.cache.use_query_cache = true 
hibernate.cache.region.factory_class = org.hibernate.cache.ehcache.SingletonEhCacheRegionFactory 
hibernate.cache.provider_configuration_file_resource_path = classpath:ehcache.xml 
net.sf.ehcache.hibernate.cache_lock_timeout = 10000 

Jede Idee, was dieses seltsame verursacht (und zufällig) Verhalten?

Antwort

1

Die Hibernate Collection Cache macht immer bestehende Einträge ungültig und sowohl die Entity als auch die Collection Caches teilen sich die gleichen , also eine soft-lock is acquired beim Aktualisieren von Daten.

Da Sie eine unidirektionale Eins-zu-viele-Verknüpfung verwenden, erhalten Sie am Ende eine Validation-Tabelle und eine Step_validation-Verknüpfungstabelle. Wann immer Sie eine Validierung hinzufügen/entfernen, müssen Sie zwei Tabellen treffen und das ist weniger effizient.

Ich schlage vor, Sie Hinzufügen der @ManyToOne Seite in der Validation Einheit und drehen Sie die @OneToMany Seite in ein zugeordnetes-Sammlungen:

@OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true, mappedBy = "step") 
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE) 
private Set<Validation> validations = new HashSet<>(); 
+0

Eigentlich habe ich keinen Link-Tabelle haben. Die Validierung hat nur einen Fremdschlüssel für Step. Ein add/remove sollte also nur eine Tabelle auslösen. Wie auch immer, ich habe meine Beziehung bidirektional gemacht und das hat den Trick gemacht! Allerdings verstehe ich nicht, warum der 2nd Level Cache eine bidirektionale Beziehung benötigt? Meine Anwendung ist voll von direktionalen (weil Bi nicht immer sinnvoll ist). Bedeutet das, dass ich alle Beziehungen umgestalten muss? Ich benutze bei allen Sammlungen eine Caching-Strategie NONSTRICT_READ_WRITE oder READ_WRITE ... – user2054927

+0

Der 'Schritt' ist das Elternteil der Assoziation und die' Validierung' ist das Kind. In einer Parent-Child-Beziehung ist Parent die Eins-zu-Viele-Seite und es ist besser, sie ebenfalls zu kartieren. Häufig können Sie dies in eine unidirektionale Verknüpfung umwandeln, die es erfordert, die Eins-zu-viele-Seite zu entfernen und nur die Viele-zu-Eins-Verknüpfung zu belassen. Eine unidirektionale Eins-zu-Viele-Verknüpfung verwendet immer eine Verknüpfungstabelle, und das ist nicht sehr praktisch. –

+0

Thx für die Klärung! – user2054927

Verwandte Themen