2010-05-11 29 views
37

Deseo utilizar JPA (eclipselink) para obtener datos de mi base de datos. La base de datos es modificada por varias otras fuentes y, por lo tanto, quiero volver a la base de datos para cada hallazgo que ejecuto. He leído varias publicaciones sobre la desactivación de la memoria caché, pero parece que no funciona. ¿Algunas ideas?Inhabilitar el almacenamiento en caché en JPA (eclipselink)

estoy tratando de ejecutar el siguiente código:

 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 dos es verdadera mientras yo quiero que sea falsa.

He intentado agregar cada uno/todo lo siguiente a mi 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"/> 

También he intentado añadir la anotación @Cache a la propia Entidad:

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

¿Estoy mal entendido algo ?

+0

James en su comentario a mi respuesta, fue la caché de apagado ( ) cuando lo probó? – Justin

+0

Lo siento, me di cuenta de esto, sí, el almacenamiento en caché estaba apagado. Todavía estoy teniendo este problema y no estoy más cerca de una solución. – James

Respuesta

34

Este comportamiento es correcto; de lo contrario, si cambia el objeto uno y el objeto dos con valores diferentes, tendrá problemas cuando los persista. Lo que está sucediendo es la llamada al objeto de cargar dos actualizaciones de la entidad cargada en la primera llamada. Deben apuntar al mismo objeto ya que SON el mismo objeto. Esto asegura que no se puedan escribir datos sucios.

Si llama a em.clear() entre las dos llamadas, la entidad uno debe separarse, su cheque devolverá falso. Sin embargo, no hay necesidad de hacer eso, eclipse link está actualizando sus datos a la última versión que supongo que es lo que quiere, ya que con frecuencia cambia.

En una nota lateral si desea actualizar estos datos utilizando JPA deberá obtener pessimistic locks en la entidad para que los datos subyacentes no puedan cambiar en la base de datos.

Usted tendrá que desactivar la caché de consultas, así sus opciones de caché se acaba de retirar la memoria caché de objetos del juego no es la caché de consultas, es por eso que no está recibiendo los nuevos resultados:

En su código:

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

O en persistence.xml:

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

Eso ayuda gracias. Tendré que mirar bloqueos pesimistas ya que los datos van a cambiar. ¿Cómo puedo agregar un hilo?dormir (10000) entre las consultas y en ese momento cambiar manualmente un atributo de MyLocation en la base de datos ¿dos (y por lo tanto uno) no reflejan este cambio? – James

+0

agregó un enlace a información sobre bloqueos pesimistas – Justin

+0

He intentado el cambio descrito en el código y persistence.xml y todavía no obtengo el valor que cambié directamente. ¿Algunas ideas? – James

3

Si se está modificando manualmente los atributos del objeto, por ejemplo MyLocation. El truco anterior (CACHE_USAGE=CacheUsage.DoNotCheckCache, o eclipselink.query-results-cache=false) no parece funcionar como lo he intentado.

Así que traté de establecer otra pista que es eclipselink.refresh, a true. entonces funciona Me refiero a que los atributos cambiados manualmente se recuperan.

Por lo que entiendo, el truco anterior solo asegura que obtiene los objetos correctos. Sin embargo, si los objetos ya se han guardado en la memoria caché, eclipselink simplemente los devuelve sin verificar la frescura del contenido de los objetos. Solo cuando la sugerencia eclipselink.refresh se establece en true, estos objetos se actualizarán para reflejar los últimos valores de atributo.

+4

¿Hava esto en su persistence.xml? Si agrego esta sugerencia a la consulta, funciona. Pero no funciona si lo defino solo en mi 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(); 

Esto funciona para mí.

+0

sorprendentemente funciona – kebyang

+0

Este es el único y el único que funcionó para mí. –

10

Sede,

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

Por la misma EntityManager APP siempre requiere que uno == dos, así que esto es correcto, no importa sus opciones de almacenamiento en caché (esto es la caché L1, o caché transaccional, que impone el aislamiento de su transacción y mantiene la identidad del objeto).

Para forzar la consulta para actualizar (y revertir los cambios que haya realizado) puede utilizar la sugerencia de consulta "eclipselink.refresh" = "true". O probablemente sea mejor, use un nuevo EntityManager para cada consulta/solicitud, o llame a clear() en su EntityManager.

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

Es la forma correcta de desactivar la memoria caché compartida (caché L2). Elimine todas las otras configuraciones, ya que no son correctas y pueden causar problemas.

EclipseLink no mantiene un caché de consultas de forma predeterminada, por lo que esas configuraciones no tendrán ningún efecto. CacheUsage tampoco es correcto, no use esto (es para consultar en la memoria).

+1

Tenga en cuenta que "eclipselink.refresh" = "true" tiene errores en las versiones actuales de EclipseLink (https://bugs.eclipse.org/bugs/show_bug.cgi?id=398074); también, es específico de EclipseLink y no es parte de JPA. Así que le aconsejo que obtenga un EntityManager nuevo cada vez que desee datos nuevos, así es como se supone que debe funcionar con JPA. – sleske

+0

Al obtener un EntityManager nuevo, no obtendrá un objeto nuevo directamente de la base de datos. La caché funciona en un nivel EntityManagerFactory, que normalmente tiene el tiempo de vida de la aplicación. – OliBlogger

7

Si desea desactivar el almacenamiento en caché sin conseguir específico del proveedor, usted podría anotar su objeto de dominio con:

@Cacheable(false) 

Aquí se muestra un ejemplo:

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

Sé que este mensaje puede ser viejo, pero estoy escribiendo para otros que necesitan ayuda. he tenido este problema y, finalmente, lo resolví por este código:

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

Funciona muy bien. Y podemos ver en javadoc de la enumeración BYPASS, está escrito que:

Omitir la caché: obtener datos directamente de la base de datos.

Debo notar que uso Weblogic 12c y TopLink como una implementación de JPA.

+0

La sugerencia de actualización mencionada anteriormente no funcionó para usted? – cen

+0

No intenté eso, porque quería omitir la caché jpa solo en algunas consultas. – AliReza19330

1

La memoria caché de primer nivel está habilitada de forma predeterminada y no puede deshabilitarla. es decir, ninguna configuración en su archivo persistence.xml deshabilitará el primer nivel de caché.

Sólo puede borrar todos los objetos del gestor de entidad llamando

entityManager.clear() 

esto hará que las consultas posteriores van a la base de datos (la primera vez) y luego los objetos se almacenan de nuevo en la memoria caché

puede forzar a cada consulta para ir a la base de datos directamente llamando

query.setHint("javax.persistence.cache.storeMode", CacheStoreMode.REFRESH); 
Cuestiones relacionadas