Question

Version rapide

Fondamentalement, je mets à jour une table Hibernate et les requêtes suivantes chargent une valeur obsolète.

Version détaillée

Mise en veille prolongée (3.3.1.GA) et EhCache (2.4.2).

Persisté Book objet avec un List<PageContent> de pages et j'ajoute une page au milieu de ce livre.J'utilise Databinder/Wicket, même si je ne pense pas que cela soit lié.

 public void createPageContent(Book book, int index) {
     Databinder.getHibernateSession().lock(book, LockMode.UPGRADE);
     PageContent page = new PageContent(book);
     book.addPage(page, index);
     CwmService.get().flushChanges(); // commits the transaction
 }

Les champs/méthode applicables dans Book sont:

@OneToMany
@JoinColumn(name="book_id")
@IndexColumn(name="pageNum")
@Cascade({CascadeType.ALL, CascadeType.DELETE_ORPHAN})
private List<PageContent> pages = new ArrayList<PageContent>();

public synchronized void addPage(PageContent page, int index) {
    pages.add(index, page);
}

Le résultat final est qu'une nouvelle page est ajoutée à une liste et que la base de données est mise à jour en conséquence et je l'ai confirmé dans ma banque de données.Cependant, la requête suivante pour une page, par exemple « Page n°4 », charge « l’ancienne » page n°4 au lieu de la nouvelle page n°4 :

criteria.add(Restrictions.eq("book", book));
criteria.add(Restrictions.eq("pageNum", pageNum));
criteria.setCacheable(true);  

Donc, je supprime à contrecœur la mise en cache des critères.Il interroge la banque de données, mais renvoie toujours la mauvaise valeur.Cependant, dans les deux cas, si j'attends environ 2 minutes, tout fonctionne comme prévu.Je suppose que la mise en cache est toujours impliquée.Les deux PageContent et Book utilisez cette stratégie de mise en cache :

@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)

J'avoue que je suis nouveau dans la mise en cache et que je viens de configurer ce fichier pour la première fois.Voici mon ehcache.xml :

<defaultCache maxElementsInMemory="10000" eternal="false" timeToIdleSeconds="120" timeToLiveSeconds="120" overflowToDisk="true" diskSpoolBufferSizeMB="30" maxElementsOnDisk="10000000" diskPersistent="false" diskExpiryThreadIntervalSeconds="120" memoryStoreEvictionPolicy="LRU" statistics="false"/>

<!-- Hibernate's Cache for keeping 'lastUpdated' data on each table.  Should never expire. -->
<cache name="org.hibernate.cache.UpdateTimestampsCache" eternal="true" />

<!-- Hibernate's Query Cache - should probably be limited -->
<cache name="org.hibernate.cache.StandardQueryCache" maxElementsInMemory="1000" />

MISE À JOUR:Suppression du @Cache les annotations sur mes objets de banque de données suppriment le problème.Bien entendu, j'aimerais mettre en cache ces objets car la modification de page est beaucoup moins fréquente que l'accès.

Alors, des idées ?Il existe également plusieurs autres problèmes liés, notamment à la suppression de pages.Tout met à jour la base de données comme prévu, mais le comportement réel est bancal.

Merci d'avance!

MISE À JOUR #2:Via le débogage, je peux confirmer que la banque de données contient les informations correctes et que lorsque la requête s'exécute, elle se rabat sur le cache de deuxième niveau, qui contient des informations sales.Je suppose que ce n'est pas à moi d'expulser du cache à chaque fois que les données changent ?

Était-ce utile?

La solution 2

J'ai découvert le problème, mais il introduit autre chose.

Fondamentalement, lors de la modification d'un Book objets List<PageContent> champ, Hibernate fait trois choses :

  1. Fait expirer l'entrée du cache TimeStamp pour les deux Book et PageContent
  2. Effectue de nombreuses requêtes pour réinitialiser le pageNum champ sur chaque PageContent objet
  3. Supprime le Book objet du cache de deuxième niveau.

Cela garantit que les requêtes ultérieures rechercheront de nouveaux objets, etc.Cependant:

  1. Hibernate ne parvient pas à supprimer chaque renuméroté PageContent objet du cache de deuxième niveau

Par conséquent, toute requête portant sur la liste des pages s'exécutera correctement, mais reviendra ensuite sur les valeurs obsolètes du cache de deuxième niveau pour les données réelles.

Je suppose que c'est parce qu'Hibernate ressent un pageNum le changement n’est pas un changement dans les données mais un changement dans la gestion en coulisses.Cependant, ce sont les données que j'aimerais lire et afficher.

La solution consiste à actualiser manuellement chaque page après l'insertion/suppression.

Autres conseils

Après CwmService.get().flushChanges(); // commits the transaction faire un commit explicite.flush() vide uniquement les modifications apportées à la base de données mais ne les valide pas.je ne suis pas sûr de flushChanges() cependant.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top