2010-05-11 16 views
37

Desidero utilizzare JPA (eclipselink) per ottenere dati dal mio database. Il database è cambiato da un certo numero di altre fonti e quindi voglio tornare al database per ogni risultato che eseguo. Ho letto un certo numero di post sulla disattivazione della cache, ma questo non sembra funzionare. Qualche idea?Disabilitare la memorizzazione nella cache in JPA (eclipselink)

Sto cercando di eseguire il codice seguente:

 EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("default"); 
     EntityManager em = entityManagerFactory.createEntityManager(); 

     MyLocation one = em.createNamedQuery("MyLocation.findMyLoc").getResultList().get(0); 

     MyLocation two = em.createNamedQuery("MyLocation.findMyLoc").getResultList().get(0);  

     System.out.println(one==two); 

uno == due è vero, mentre io voglio che sia falsa.

Ho provato ad aggiungere ogni/tutte le seguenti alla mia persistence.xml

<property name="eclipselink.cache.shared.default" value="false"/> 
<property name="eclipselink.cache.size.default" value="0"/> 
<property name="eclipselink.cache.type.default" value="None"/> 

Ho anche provato ad aggiungere l'annotazione @Cache alla propria Entità:

@Cache(
    type=CacheType.NONE, // Cache nothing 
    expiry=0, 
    alwaysRefresh=true 
) 

Sto malinteso qualcosa ?

+0

James nel tuo commento alla mia risposta, è stato il caching off ( ) quando lo hai testato? – Justin

+0

Mi dispiace, ho notato questo, sì il caching era spento. Sto ancora avendo questo problema e non sono più vicino a una soluzione. – James

risposta

34

Questo comportamento è corretto, altrimenti se si modifica l'oggetto uno e l'oggetto due con valori diversi si avranno problemi durante la loro permanenza. Quello che sta accadendo è la chiamata a caricare l'oggetto due aggiornamenti l'entità caricata nella prima chiamata. Devono puntare allo stesso oggetto poiché sono lo stesso oggetto. Ciò garantisce che i dati sporchi non possano essere scritti.

Se si chiama em.clear() tra le due chiamate, l'entità 1 deve essere scollegata, il controllo restituirà false. Non c'è comunque bisogno di farlo, il collegamento di eclipse è infatti l'aggiornamento dei dati al più recente che suppongo sia ciò che si desidera dal momento che cambia frequentemente.

Nota a margine se si desidera aggiornare questi dati utilizzando JPA, sarà necessario ottenere pessimistic locks nell'entità in modo che i dati sottostanti non possano essere modificati nel DB.

Sarà necessario disattivare la cache delle query, nonché le opzioni di cache sono stati solo di rimuovere la cache degli oggetti dal gioco non è la cache delle query, è per questo che non stanno ottenendo i nuovi risultati:

Nel codice:

em.createNamedQuery("MyLocation.findMyLoc").setHint(QueryHints.CACHE_USAGE, CacheUsage.DoNotCheckCache).getResultList().get(0); 

O in persistence.xml:

<property name="eclipselink.query-results-cache" value="false"/> 
+0

Questo ti aiuta a ringraziarti. Dovrò guardare le serrature pessimistiche mentre i dati cambieranno. Come poi se aggiungo una discussione.sleep (10000) tra le query e in quel momento modificare manualmente un attributo di MyLocation nel database fa due (e quindi uno) non riflette questa modifica? – James

+0

aggiunto un collegamento ad alcune informazioni sui blocchi pessimistici – Justin

+0

Ho provato la modifica descritta nel codice e persistence.xml e ancora non ottengo il valore che ho modificato direttamente. Qualche idea? – James

3

Se la modifica manualmente gli attributi dell'oggetto, per esempio MyLocation. Il trucco precedente (CACHE_USAGE=CacheUsage.DoNotCheckCache o eclipselink.query-results-cache=false) non sembra funzionare come ho provato.

Così ho provato a impostare un altro suggerimento che è eclipselink.refresh, a true. allora funziona. Voglio dire, gli attributi modificati manualmente vengono recuperati.

Quindi, come ho capito, il trucco sopra assicura solo che ottiene gli oggetti corretti. Tuttavia, se gli oggetti sono già stati memorizzati nella cache, eclipselink li restituisce senza controllare la freschezza dei contenuti degli oggetti. Solo quando il suggerimento eclipselink.refresh è impostato su true, questi oggetti verranno aggiornati per riflettere gli ultimi valori di attributo.

+4

Hava hai impostato questo nel tuo persistence.xml? Se aggiungo questo suggerimento alla query funziona. Ma non funziona se lo definisco solo nel mio persistence.xml. – Christian

22
final Query readQuery = this.entityManager.createQuery(selectQuery); 
readQuery.setParameter(paramA, valueA); 

// Update the JPA session cache with objects that the query returns. 
// Hence the entity objects in the returned collection always updated. 
readQuery.setHint(QueryHints.REFRESH, HintValues.TRUE); 

entityList = readQuery.getResultList(); 

Questo funziona per me.

+0

questo funziona sorprendentemente – kebyang

+0

Questo è l'unico SOLO che ha funzionato per me. –

10

Sede,

http://wiki.eclipse.org/EclipseLink/UserGuide/JPA/Basic_JPA_Development/Caching

Per lo stesso EntityManager JPA richiede sempre che uno == due, quindi questo è corretto, non importa le opzioni di caching (questa è la cache L1, o di cache transazionale, che applica l'isolamento della transazione e mantiene l'identità dell'oggetto).

Per forzare la query ad aggiornare (e annullare eventuali modifiche apportate) è possibile utilizzare il suggerimento di query "eclipselink.refresh" = "true". O probabilmente meglio, usa un nuovo EntityManager per ogni query/richiesta o chiama clear() sul tuo EntityManager.

<property name="eclipselink.cache.shared.default" value="false"/> 

È il modo corretto per disabilitare la cache condivisa (cache L2). Rimuovi tutte le altre impostazioni perché non sono corrette e possono causare problemi.

EclipseLink non mantiene una cache di query per impostazione predefinita, pertanto tali impostazioni non avranno alcun effetto. Anche CacheUsage non è corretto, non utilizzarlo (è per l'interrogazione in memoria).

+1

Nota che "eclipselink.refresh" = "true" è buggato nelle versioni correnti di EclipseLink (https://bugs.eclipse.org/bugs/show_bug.cgi?id=398074); inoltre, è specifico per EclipseLink e non fa parte di JPA. Quindi consiglierei di ottenere un nuovo EntityManager ogni volta che vuoi dati nuovi - è così che dovrebbe funzionare con JPA. – sleske

+0

Ottenere un nuovo EntityManager non otterrà un nuovo oggetto direttamente dal database. La cache funziona su un livello EntityManagerFactory, che normalmente ha il tempo di vita dell'applicazione. – OliBlogger

7

Se si desidera disabilitare la cache senza ottenere fornitore specifico, si potrebbe annotare l'oggetto dominio con:

@Cacheable(false) 

Ecco un esempio:

@Entity 
@Table(name="SomeEntity") 
@Cacheable(false) 
public class SomeEntity { 
    // ... 
} 
3

So che questo post potrebbe essere vecchio, ma sto scrivendo per gli altri che hanno bisogno di aiuto. Ho avuto questo problema e alla fine ho risolto da questo codice:

em.createNamedQuery("findAll").setHint(QueryHints.CACHE_RETRIEVE_MODE, CacheRetrieveMode.BYPASS).getResultList(); 

Funziona davvero bene. E possiamo vedere in javadoc dell'enumerazione BYPASS, è scritto che:

Bypassare la cache: recupera i dati direttamente dal database.

Dovrei notare che utilizzo Weblogic 12c e TopLink come implementazione JPA.

+0

Il suggerimento di aggiornamento di cui sopra non ha funzionato per te? – cen

+0

Non l'ho provato, perché volevo aggirare la cache jpa solo in alcune query. – AliReza19330

1

La cache di primo livello è abilitata per impostazione predefinita e non è possibile disabilitarla. Ad esempio, nessuna impostazione nel file persistence.xml disabiliterà la cache di primo livello.

È possibile cancellare solo tutti gli oggetti entità gestore chiamando

entityManager.clear() 

questo renderà query successive vanno al database (la prima volta) e poi gli oggetti vengono ancora memorizzati nella cache

È possibile forzare ogni query di andare direttamente al database chiamando

query.setHint("javax.persistence.cache.storeMode", CacheStoreMode.REFRESH); 
Problemi correlati