Come mantenere la coerenza della cache di Hibernate eseguendo due applicazioni Java?

StackOverflow https://stackoverflow.com/questions/48733

  •  09-06-2019
  •  | 
  •  

Domanda

Il nostro progetto prevede una jvm che è una jboss/webapp (lettura/scrittura) utilizzata per mantenere i dati tramite ibernazione (utilizzando jpa) nel db.Il modello ha 10-15 classi persistenti con 3-5 livelli di profondità nelle relazioni.

Abbiamo quindi una jvm separata che è il server che utilizza questi dati.Dato che è in esecuzione continua, abbiamo solo una lunga sessione db (sola lettura).

Al momento non è coinvolta alcuna cache intra-jvm, quindi segnaliamo manualmente una jvm dall'altra.

Ora, quando la webapp modifica alcuni dati, segnala al server di ricaricare i dati modificati.Ciò che abbiamo scoperto è che dobbiamo dire a Hibernate di eliminare i dati e quindi di ricaricarli.Effettuare semplicemente un recupero/unione con il db non funziona, principalmente per quanto riguarda gli oggetti a diversi livelli nella gerarchia.

Qualche idea sul fatto che ci sia qualcosa di fondamentalmente sbagliato in questo progetto o se qualcuno lo sta facendo e ha avuto più fortuna lavorando con l'ibernazione sulle ricariche.

Grazie, Chris

È stato utile?

Soluzione

Una sessione di Hibernate carica tutti i dati letti dal DB in quello che chiamano cache di primo livello.Una volta caricata una riga dal DB, qualsiasi recupero successivo di una riga con lo stesso PK restituirà i dati da questa cache.Inoltre, le garanzie di Hibernate fanno riferimento all'uguaglianza per oggetti con lo stesso PK in una singola sessione.

Da quanto ho capito, la tua applicazione server di sola lettura non chiude mai la sessione di ibernazione.Pertanto, quando il DB viene aggiornato dall'applicazione di lettura-scrittura, la sessione sul server di sola lettura non è a conoscenza della modifica.In effetti, l'applicazione di sola lettura carica una copia in memoria del database e utilizza quella copia, che a tempo debito diventa obsoleta.

La linea d'azione più semplice e migliore che posso suggerire è chiudere e aprire le sessioni secondo necessità.Questo elude l’intero problema.Le sessioni di ibernazione sono intese come una finestra per un'interazione di breve durata con il DB.Sono d'accordo che vi sia un miglioramento delle prestazioni non ricaricando l'oggetto grafico ancora e ancora;ma devi misurarlo e convincerti che ne vale la pena.

Un'altra opzione è chiudere e riaprire periodicamente la sessione.Ciò garantisce che l'applicazione di sola lettura funzioni con dati non più vecchi di un determinato intervallo di tempo.Ma c'è sicuramente una finestra in cui l'applicazione di sola lettura funziona con dati obsoleti (sebbene il design garantisca che prima o poi ottenga i dati aggiornati).Ciò potrebbe essere consentito in molte applicazioni: è necessario valutare la propria situazione.

La terza opzione è utilizzare a cache di secondo livello implementazione e utilizzare sessioni di breve durata.Esistono vari pacchetti di memorizzazione nella cache che funzionano con Hibernate con relativi meriti e demeriti.

Altri suggerimenti

Chris, sono un po' confuso riguardo alla tua situazione.Se ho capito bene, hai sia un'app Web (lettura/scrittura) che un'applicazione autonoma (sola lettura?) che utilizza Hibernate per accedere a un database condiviso.Le modifiche apportate con l'app Web non sono visibili nell'app autonoma.È giusto?

In tal caso, hai preso in considerazione l'utilizzo di una diversa implementazione della cache di secondo livello?Mi chiedo se potresti essere in grado di utilizzare una cache in cluster condivisa sia dall'applicazione Web che dall'applicazione autonoma.Credo che SwarmCache, che è integrato con Hibernate, lo consentirà, ma non l'ho provato personalmente.

In generale, però, dovresti sapere che il contenuto di una determinata cache non sarà mai a conoscenza dell'attività di un'altra applicazione (ecco perché suggerisco di condividere la cache con entrambe le app).Buona fortuna!

Dal mio punto di vista, dovresti cambiare la cache di ibernazione sottolineata con quella che supporta la modalità cluster.Potrebbe essere un JBoss Cache o a Cassa dello sciame.Il primo ha un migliore supporto per la sincronizzazione dei dati (replica e invalidazione) e supporta anche JTA.

Quindi sarai in grado di configurare la sincronizzazione della cache tra webapp e server.Controlla anche il livello di isolamento se utilizzerai JBoss Cache.Credo che dovresti usare READ_COMMITTED modalità se desideri ottenere nuovi dati su un server dalla stessa sessione.

La pratica più utilizzata è quella di avere un file Gestore di entità gestite da contenitori in modo che due o più applicazioni nello stesso contenitore (ad esempio Glassfish, Tomcat, Websphere) possano condividere le stesse cache.Ma se non usi un contenitore dell'applicazione, perché usi Play!per esempio, creerei alcuni servizi web nel file Applicazione primaria per leggere/scrivere in modo coerente nella cache.

Penso che l'utilizzo di dati obsoleti sia una porta aperta al disastro.Proprio come i Singleton diventano Multiton, le applicazioni di sola lettura sono spesso a scrivi qualche volta.

Cintura e bretelle :)

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top