Pregunta

ACTUALIZAR:EJEMPLO PARA ACLARAR Voy a poner un ejemplo de lo que está pasando sólo para aclarar la situación en mi aplicación Spring + Hibernate.Imagine que tengo estas dos entidades (supongamos que también existen captadores y definidores)

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

  @OneToOne
  private Class2 object2;
}

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

  @OneToOne
  private Class1 object2;
}

Entonces, en mi base de datos tengo dos tablas para mapear cada instancia de cada objeto.Supongamos que tengo almacenados en la base de datos estos objetos:

  • objetoA (clase Clase1):id = 1, objeto2 = objetoB
  • objetoB (clase Clase2):id = 2, objeto2 = objetoA
  • objetoC (clase Clase2):id = 3 , object2 = null lo que significa que A y B están vinculados.Supongamos que ahora quiero vincular el objetoA al objetoC.Significa que también tengo que eliminar el enlace en el objeto B.

Para hacer esto hago lo siguiente:

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

El objeto restaurado A ahora es:

  • objetorestauradoA (clase = Clase1) id = 1, objeto2 = objetoC

aunque en la base de datos hay:

  • objetorestauradoA (clase = Clase1) id = 1, objeto2 = objetoB

El método de búsqueda no ha buscado en la base de datos y obtuve la búsqueda anterior aunque tengo mi consulta y los cachés de segundo nivel deshabilitados.El método find sólo va al DAO donde se ejecuta en el entityManager.find(Class1.class, id) ¿Cómo puedo hacer mi segunda búsqueda en la base de datos?

Gracias


(Explicación completa)

Hola,

Tengo una aplicación que usa Spring 3 e Hibernate.Tengo una entidad llamada Clase1 que está almacenada en una base de datos.Esta entidad tiene un vínculo OneToOne con otra entidad llamada Clase2.Class2 tiene otro vínculo OneToOne con Class1 y ambos vínculos tienen una propiedad única establecida en verdadero.

Tengo el siguiente código en mi controlador:

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

El método guardar en myService utilizará el administrador de entidades para conservar los datos, pero antes de eso verificará la asociación anterior entre el objeto Clase1 y el objeto Clase2 para eliminarla en caso de que un nuevo Objeto Clase2 se haya configurado en la instancia de Clase1.Por esa razón tengo que llamar al método de búsqueda nuevamente para ver qué hay en mi base de datos.

En el servicio:

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

El problema es que objectFromDB en el Servicio no es el mismo que cuando hice myService.find(id) en el controlador.El problema es que no lo busca en la base de datos sino que lo busca en la memoria.Lo sé porque no se registra ninguna declaración SQL cuando se llama al segundo método find().Como hice setObject2() en el objeto almacenadoData, obtengo exactamente este objeto cuando llamo al método de búsqueda por segunda vez, y la base de datos no contiene esto porque aún no ha persistido.

Intenté deshabilitar el caché en mi configuración solo para intentarlo, pero todavía sucede.Tengo un ehCache con esta configuración:

En persistence.xml tengo estas propiedades (he configurado ambos cachés en falso):

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

En mi ehcache.xml lo configuré en 0 maxElementsInMemory y overflowToDisk en falso para deshabilitarlo también.

¿Hay alguna manera de evitar esta situación?

Gracias.

¿Fue útil?

Solución 2

Vale, lo descubro.El problema es que hibernación busca los objetos en su sesión antes de buscar en la base de datos.así que tuve que separar el objeto de la sesión antes de modificarlo.Para hacerlo en hibernación:

    //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

Otros consejos

No estoy seguro de haber entendido bien, pero por si acaso...


Hay dos métodos para cargar un objeto.Hay una diferencia si el objeto no está en el contexto de memoria actual:

  • Uno va con seguridad a la base de datos, devuelve la instancia si existe o nula en caso contrario.
  • El otro simplemente crea un Proxy con la identificación correcta, sin ir inmediatamente a la base de datos, y lo procesará según sea necesario en operaciones posteriores (posiblemente al vaciar).

Parece que estás usando el segundo, ¿tal vez podrías probar el primero y ver si resuelve tu problema?

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top