web-dev-qa-db-fra.com

Désactiver la mise en cache dans JPA (eclipselink)

Je souhaite utiliser JPA (eclipselink) pour obtenir des données de ma base de données. La base de données est modifiée par un certain nombre d'autres sources et je veux donc revenir à la base de données pour chaque recherche que j'exécute. J'ai lu un certain nombre de messages sur la désactivation du cache, mais cela ne semble pas fonctionner. Des idées?

J'essaie d'exécuter le code suivant:

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

un == deux est vrai alors que je veux que ce soit faux.

J'ai essayé d'ajouter chacun/tous les éléments suivants à mon 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"/>

J'ai également essayé d'ajouter l'annotation @Cache à l'entité elle-même:

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

Suis-je en train de mal comprendre quelque chose?

43
James

Ce comportement est correct, sinon si vous modifiez l'objet un et l'objet deux avec des valeurs différentes, vous aurez des problèmes lors de leur persistance. Ce qui se passe, c'est que l'appel à charger l'objet deux met à jour l'entité chargée lors du premier appel. Ils doivent pointer vers le même objet car ils SONT le même objet. Cela garantit que les données sales ne peuvent pas être écrites.

Si vous appelez em.clear () entre les deux appels, l'entité 1 devrait se détacher, votre chèque retournera faux. Il n'y a cependant pas besoin de le faire, le lien Eclipse est en fait la mise à jour de vos données au plus tard, ce qui, je suppose, est ce que vous voulez car il change fréquemment.

De plus, si vous souhaitez mettre à jour ces données à l'aide de JPA, vous devrez obtenir verrous pessimistes sur l'entité afin que les données sous-jacentes ne puissent pas changer dans la base de données.

Vous devrez également désactiver le cache de requêtes. Vos options de cache supprimaient simplement le cache d'objets de la lecture et non le cache de requêtes, c'est pourquoi vous n'obtenez pas les nouveaux résultats:

Dans votre code:

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

Ou dans persistence.xml:

<property name="eclipselink.query-results-cache" value="false"/>
39
Justin
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();

Cela fonctionne pour moi.

25
Binu S

Si vous souhaitez désactiver la mise en cache sans être spécifique au fournisseur, vous pouvez annoter votre objet de domaine avec:

@Cacheable(false)

Voici un exemple:

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

Voir,

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

Pour le même EntityManager JPA, il faut toujours un == deux, donc c'est correct, peu importe vos options de mise en cache (c'est le cache L1, ou cache transactionnel, qui applique votre isolation de transaction et maintient l'identité de l'objet).

Pour forcer la requête à actualiser (et annuler toutes les modifications que vous avez apportées), vous pouvez utiliser l'indicateur de requête "eclipselink.refresh" = "true". Ou mieux, utilisez un nouvel EntityManager pour chaque requête/demande, ou appelez clear () sur votre EntityManager.

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

Est la bonne façon de désactiver le cache partagé (cache L2). Veuillez supprimer tous vos autres paramètres car ils ne sont pas corrects et peuvent provoquer des problèmes.

EclipseLink ne gère pas de cache de requêtes par défaut, donc ces paramètres n'auront aucun effet. CacheUsage n'est pas non plus correct, ne l'utilisez pas (c'est pour les requêtes en mémoire).

10
James

Si vous modifiez manuellement les attributs de l'objet, par exemple MyLocation. L'astuce ci-dessus (CACHE_USAGE=CacheUsage.DoNotCheckCache, ou eclipselink.query-results-cache=false) ne semble pas fonctionner comme j'ai essayé.

J'ai donc essayé de définir un autre indice qui est eclipselink.refresh, à true. alors ça marche. Je veux dire que les attributs modifiés manuellement sont récupérés.

Donc, si je comprends bien, l'astuce ci-dessus ne garantit que l'obtention des bons objets. Cependant, si les objets ont déjà été mis en cache, eclipselink les renvoie simplement sans vérifier la fraîcheur du contenu des objets. Uniquement lorsque l'indice eclipselink.refresh est défini sur true, ces objets seront-ils actualisés pour refléter les dernières valeurs d'attribut.

3
Robin

Le cache de premier niveau est activé par défaut et vous ne pouvez pas le désactiver. c'est-à-dire qu'aucun paramètre dans votre fichier persistence.xml ne désactivera le cache de premier niveau.

Vous ne pouvez effacer tous les objets du gestionnaire d'entités qu'en appelant

entityManager.clear()

cela fera aller les requêtes suivantes à la base de données (la première fois), puis les objets seront à nouveau stockés dans le cache

Vous pouvez forcer chaque requête à accéder directement à la base de données en appelant

query.setHint("javax.persistence.cache.storeMode", CacheStoreMode.REFRESH);
3
Michael

Je sais que ce message est peut-être ancien, mais j'écris pour ceux qui ont besoin d'aide. J'ai eu ce problème et finalement je l'ai résolu par ce code:

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

Ça marche vraiment bien. Et nous pouvons voir en javadoc de l'énumération BYPASS, il est écrit que:

Contournez le cache: obtenez les données directement de la base de données.

Je dois noter que j'utilise Weblogic 12c et TopLink comme implémentation JPA.

3
AliReza19330