2015-06-19 9 views
6

Sto riscontrando un problema in cui un'istanza Validation viene aggiunta a una raccolta su un'istanza Step. dichiarazione è la seguente:Incoerenza nella cache - L'entità non è sempre persistente nella raccolta cache

Passo classe:

@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); 
    } 

} 

classe di convalida:

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

Entrambe le classi sono Cacheable con una strategia READ_WRITE applicata. Anche la raccolta unidirezionale di Validation s viene memorizzata nella cache con la stessa strategia.

Ci si aspetterebbe quando una transazione di lettura/scrittura che richiama addValidation(new Validation('userName')); si impegna, il nuovo Validation sarà visibile in una successiva transazione di sola lettura. La cosa strana è che a volte funziona e talvolta non funziona ...

La prima operazione ha sempre esito positivo; vediamo che la nuova convalida è persistita nel database e la proprietà della versione di Step (per le approssimazioni del blocco ottimistico) viene incrementata. Ma a volte, la seconda transazione di lettura contiene un'istanza Step con una Validation Collection vuoto ...

nostro Hibernate caching configurazione è la seguente:

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 

Qualche idea di cosa sta causando questo strano (e casuale) comportamento?

risposta

1

Il Hibernate Collection Cache invalida sempre le voci esistenti e entrambe le casse Entity e Collection condividono lo stesso AbstractReadWriteEhcacheAccessStrategy, quindi un soft-lock is acquired durante l'aggiornamento dei dati.

Poiché si utilizza un'associazione unidirezionale uno-a-molti, si finirà con una tabella Validation e una tabella di collegamento Step_validation. Ogni volta che aggiungi/rimuovi una convalida devi colpire due tavoli e questo è meno efficiente.

vi consiglio di aggiungere il lato @ManyToOne nell'entità Validation e ruotare il lato @OneToMany in una mappato-per collezione:

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

In realtà, non ho una tabella di collegamento. La validazione ha solo una chiave straniera per Step. Quindi un add/remove dovrebbe attivare solo una tabella. Ad ogni modo, ho reso il mio rapporto bidirezionale e questo ha fatto il trucco! Tuttavia, non capisco perché la cache di secondo livello richiede una relazione bidirezionale? La mia applicazione è piena di quelli direzionali (perché bi non è sempre significativo). Questo significa che devo refactoring tutte le relazioni? Uso su tutte le raccolte una strategia di memorizzazione nella cache NONSTRICT_READ_WRITE o READ_WRITE ... – user2054927

+0

Il 'Passo' è il genitore dell'associazione e' Validazione' è il bambino. In una relazione padre-figlio, il genitore è il lato uno-a-molti ed è anche meglio mapparlo. Spesso, è possibile trasformarlo in un'associazione unidirezionale, che richiede la rimozione del lato uno-a-molti e lasciando solo l'associazione many-to-one. Un'associazione unidirezionale uno-a-molti usa sempre una tabella dei collegamenti e non è molto pratica. –

+0

Thx per chiarire questo! – user2054927

Problemi correlati