Question

MISE À JOUR: EXEMPLE DE CLARIFIER Je vais mettre un exemple de ce qui se passe juste pour clarifier la situation dans mon application Spring + Hibernate. Imaginez que j'ai ces deux entités (getters et setters existe Supposons aussi)

@Entity
public class Class1(){
  private Integer id;

  @OneToOne
  private Class2 object2;
}

@Entity
public class Class2(){
  private Integer id;

  @OneToOne
  private Class1 object2;
}

Donc, dans ma base de données que j'ai deux tables pour cartographier chaque instance de chaque objet. Supposons que j'ai stocké dans la base de données de ces objets:

  • objectA (classe Class1): id = 1, object2 = objectB
  • objectB (classe Class2): id = 2, object2 = objectA
  • ObjectC (classe Class2): id = 3, object2 = null ce qui signifie une anb B sont liés. Supposons maintenant que je veux créer un lien objectA à ObjectC. Cela signifie que je dois supprimer le lien dans la objectB aussi.

Pour faire cela, je ne l'avez choisi:

//I get the objectA from database
Class1 storedObjectA = myservice.find(objectAId);
//Now in storedObject1 I have the same as what it is stored as objectA

//I change only the object2 attribute of it
storedObject1.setObject2(objectC);

//I search again in the database to see objectA
Class1 reStoredObjectA = myservice.find(objectAId);

restoredObjectA est maintenant:

  • restoredObjectA (class = Class1) id = 1, object2 = ObjectC

bien que dans la base de données il y a:

  • restoredObjectA (class = Class1) id = 1, object2 = objectB

La découverte de la méthode n'a pas recherché dans la base de données et j'ai obtenu la recherche précédente que je me caches requête et deuxième niveau désactivés. La méthode ne va trouver à l'OAC où il exécute sur le entityManager.find (Class1.class, id) Comment puis-je faire mon deuxième searchs de trouver dans la base de données?

Merci


(explication complète)

Bonjour,

J'ai une application qui utilise Spring 3 et Hibernate. J'ai une entité nommée Class1 qui est stocké dans une base de données. Cette entité a un lien OneToOne à une autre entité appelée Classe2. Class2 a un autre OneToOne Lien vers Class1, et les deux ont des liens propriété unique définie sur true.

Je le code suivant dans mon contrôleur:

//I have an object called dataFromUser which is instance of Class1 and
// it is obtained via @ModelAttribute annotation from a form

Integer id = dataFromUser.getId();

//I get correctly the stored object from the database
Class1 storedData = myService.find(id); //this will call em.find of hibernate

//I set to the stored data the attribute I want to change
storedData.setObject2();

//I save again the object
myService.save(storedData);

La méthode de sauvegarde en myService utilisera le gestionnaire d'entités pour conserver les données, mais avant qu'il vérifiera l'association précédente entre l'objet Class1 et objet Class2 de le supprimer dans le cas où un nouvel objet Class2 a mis à l'instance de Class1. Pour cette raison, je dois appeler la méthode de trouver à nouveau pour voir ce qui est dans ma base de données

Dans le service:

@Transactional
public void save(Class1 object1){
   Class1 objectFromDB =  myDAO.find(object1.getId());
   // ....  update the old object and save
}

Le problème est que objectFromDB dans le service n'est pas la même chose que quand je l'ai myService.find (id) dans le contrôleur. Le problème est qu'il ne cherche pas dans la base de données, mais il est à la recherche dans la mémoire. Je sais parce qu'il n'y a pas de méthode instruction SQL connecté lorsque la deuxième find () est appelée. Comme je l'avais fait setObject2 () sur l'objet storedData je reçois exactement cet objet quand je l'appelle méthode de recherche pour la deuxième fois, et la base de données ne contient pas parce qu'il n'a pas encore persisté.

J'ai essayé de désactiver le cache dans ma configuration juste pour essayer, mais il se passe encore. J'ai un ehcache avec cette configuration:

Dans persistence.xml Je ces propriétés (j'ai mis à faux les deux caches):

    <properties>
     <!-- Hibernate 3.5.0 - try org.hibernate.cache.* package -->
  <property name="hibernate.cache.provider_class"
               value="net.sf.ehcache.hibernate.SingletonEhCacheProvider" />
   <property name="hibernate.cache.use_query_cache" value="false" />
  <property name="hibernate.cache.use_second_level_cache" value="false" />
  <property name="hibernate.generate_statistics" value="true" />
  <property name="hibernate.cache.use_structured_entries" value="false" />
  <property name="hibernate.format_sql" value="true" />
  <!-- http://www.jroller.com/eyallupu/entry/hibernate_s_hbm2ddl_tool -->
  <!-- create, create-drop, update, validate -->
  <property name="hibernate.hbm2ddl.auto" value="update" />
    </properties>  

Dans mon ehcache.xml je l'ai mis à 0 maxElementsInMemory et overflowToDisk false pour le désactiver aussi.

 

Y at-il moyen d'éviter cette situation?

Merci.

Était-ce utile?

La solution 2

OK, je trouve dehors. Le problème est que hibernate recherche les objets à sa session avant de rechercher dans la base de données. donc je devais détaché l'objet à la session avant de le modifier. Pour ce faire en veille prolongée:

    //being em my EntityManager instance
    Session session = (Session) em.getDelegate();
    session.evict(plan); 
    //Now the find object will not get the object wich is in session 
    //but the one in database

Autres conseils

Je ne suis pas sûr d'avoir bien compris, mais juste au cas où ...


Il y a deux méthodes pour charger un objet . Il y a une différence si l'objet n'est pas dans le contexte actuel de la mémoire:

  • On va bien sûr à la base de données, retourne l'instance si elle existe ou nul autre.
  • L'autre crée simplement un proxy avec l'ID correct, sans passer immédiatement à la base de données, et le traiter selon les besoins dans les opérations ultérieures (éventuellement lors du rinçage).

Vous semblez être en utilisant le second, peut-être vous pouvez essayer le premier et voir si cela résout votre problème?

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