java - mundo - hibernate web application
¿Cuáles son las diferencias entre los diferentes métodos de ahorro en Hibernate? (8)
Hibernate tiene un puñado de métodos que, de una forma u otra, toman su objeto y lo ponen en la base de datos. ¿Cuáles son las diferencias entre ellos, cuándo usarlos y por qué no existe un solo método inteligente que sepa cuándo usar qué?
Los métodos que he identificado hasta ahora son:
- salvar()
- actualizar()
- saveOrUpdate ()
- saveOrUpdateCopy ()
- unir()
- persistir()
Aquí está mi entendimiento de los métodos. Principalmente, estos se basan en la API ya que no los utilizo en la práctica.
saveOrUpdate Las llamadas se guardan o actualizan dependiendo de algunas comprobaciones. Por ejemplo, si no existe un identificador, se llama guardar. De lo contrario, se llama a la actualización.
save Persists una entidad. Asignará un identificador si uno no existe. Si uno lo hace, básicamente está haciendo una actualización. Devuelve el ID generado de la entidad.
actualización Intenta persistir la entidad utilizando un identificador existente. Si no existe un identificador, creo que se lanza una excepción.
saveOrUpdateCopy Esto está en desuso y ya no se debe usar. En cambio, hay ...
fusionar Ahora aquí es donde mi conocimiento comienza a fallar. Lo importante aquí es la diferencia entre entidades transitorias, aisladas y persistentes. Para obtener más información sobre los estados de los objetos, mira aquí . Con guardar y actualizar, se trata de objetos persistentes. Están vinculados a una Sesión así que Hibernate sabe qué ha cambiado. Pero cuando tienes un objeto transitorio, no hay sesión involucrada. En estos casos, debe usar merge para las actualizaciones y persistir para guardarlas.
persist Como se mencionó anteriormente, esto se usa en objetos transitorios. No devuelve la ID generada.
En realidad, la diferencia entre los métodos hibernate save()
y persist()
depende de la clase generadora que estamos utilizando.
Si nuestra clase de generador está asignada, entonces no hay diferencia entre los métodos save()
y persist(
). Porque el generador ''asignado'' significa que, como programador, debemos dar el valor de la clave primaria para guardar en la base de datos correcta [Espero que conozcas este concepto de generadores] En caso de otra clase de generador asignada, supongamos que si nuestro nombre de clase generador es Incremento significa hibernate auto asignará el valor de la identificación de la clave principal a la base de datos [que no sea el generador asignado, la hibernación solo se utiliza para cuidar el valor de la identificación de la clave principal recuerda], así que en este caso si llamamos al método save()
o persist()
insertará el registro en la base de datos normalmente. Pero oiga que cosa es, el método save()
puede devolver ese valor de identificación de clave primaria que es generado por hibernación y podemos verlo por
long s = session.save(k);
En este mismo caso, persist()
nunca devolverá ningún valor al cliente.
Encontré un buen ejemplo que muestra las diferencias entre todos los métodos de guardado de hibernación:
http://www.journaldev.com/3481/hibernate-session-merge-vs-update-save-saveorupdate-persist-example
En resumen, de acuerdo con el enlace de arriba:
salvar()
- Podemos invocar este método fuera de una transacción. Si usamos esto sin transacción y tenemos una cascada entre entidades, entonces solo se guarda la entidad primaria a menos que limpiemos la sesión.
- Por lo tanto, si hay otros objetos asignados desde el objeto primario, se guardan en el momento de confirmar la transacción o cuando purgamos la sesión.
persistir()
- Es similar al uso de save () en la transacción, por lo que es seguro y se encarga de cualquier objeto en cascada.
saveOrUpdate ()
Se puede usar con o sin la transacción, y al igual que save (), si se usa sin la transacción, las entidades asignadas no se guardarán sino que limpiamos la sesión.
Resultados en consultas de inserción o actualización basadas en los datos proporcionados. Si los datos están presentes en la base de datos, se ejecuta la consulta de actualización.
actualizar()
- La actualización de Hibernate debe usarse cuando sabemos que solo estamos actualizando la información de la entidad. Esta operación agrega el objeto de entidad al contexto persistente y los cambios adicionales se rastrean y guardan cuando se confirma la transacción.
- Por lo tanto, incluso después de llamar a la actualización, si establecemos cualquier valor en la entidad, se actualizarán cuando la transacción se comprometa.
unir()
- La fusión de Hibernate se puede usar para actualizar valores existentes; sin embargo, este método crea una copia del objeto de entidad pasado y lo devuelve. El objeto devuelto forma parte del contexto persistente y se realiza un seguimiento de los cambios, el objeto pasado no se rastrea. Esta es la principal diferencia con merge () de todos los otros métodos.
También para ejemplos prácticos de todos estos, consulte el enlace que mencioné anteriormente, muestra ejemplos de todos estos métodos diferentes.
Este enlace explica de buena manera:
http://www.stevideter.com/2008/12/07/saveorupdate-versus-merge-in-hibernate/
Todos tenemos esos problemas que encontramos con la suficiente frecuencia que cuando los vemos de nuevo, sabemos que hemos resuelto esto, pero no recuerdo cómo.
La excepción NonUniqueObjectException lanzada al usar Session.saveOrUpdate () en Hibernate es una de las mías. Agregaré nuevas funcionalidades a una aplicación compleja. Todas las pruebas de mi unidad funcionan bien. Luego, al probar la interfaz de usuario, tratando de guardar un objeto, empiezo a recibir una excepción con el mensaje "un objeto diferente con el mismo valor de identificador ya estaba asociado a la sesión". Aquí hay un código de ejemplo de Java Persistence con Hibernate.
Session session = sessionFactory1.openSession();
Transaction tx = session.beginTransaction();
Item item = (Item) session.get(Item.class, new Long(1234));
tx.commit();
session.close(); // end of first session, item is detached
item.getId(); // The database identity is "1234"
item.setDescription("my new description");
Session session2 = sessionFactory.openSession();
Transaction tx2 = session2.beginTransaction();
Item item2 = (Item) session2.get(Item.class, new Long(1234));
session2.update(item); // Throws NonUniqueObjectException
tx2.commit();
session2.close();
Para comprender la causa de esta excepción, es importante comprender los objetos separados y lo que sucede cuando se llama a saveOrUpdate () (o simplemente update ()) en un objeto separado.
Cuando cerramos una sesión de Hibernate individual, los objetos persistentes con los que estamos trabajando se separan. Esto significa que los datos todavía están en la memoria de la aplicación, pero Hibernate ya no es responsable de rastrear los cambios en los objetos.
Si luego modificamos nuestro objeto separado y queremos actualizarlo, tenemos que volver a conectar el objeto. Durante ese proceso de readaptación, Hibernate verificará si hay otras copias del mismo objeto. Si encuentra alguno, tiene que decirnos que ya no sabe cuál es la copia "real". Quizás se hicieron otros cambios a esas otras copias que esperamos que se guarden, pero Hibernate no las conoce, porque no las estaba administrando en ese momento.
En lugar de guardar datos posiblemente malos, Hibernate nos cuenta sobre el problema a través de NonUniqueObjectException.
Entonces, ¿qué vamos a hacer? En Hibernate 3, tenemos merge () (en Hibernate 2, use saveOrUpdateCopy ()). Este método obligará a Hibernate a copiar cualquier cambio de otras instancias separadas en la instancia que desee guardar, y así fusionará todos los cambios en la memoria antes del guardado.
Session session = sessionFactory1.openSession();
Transaction tx = session.beginTransaction();
Item item = (Item) session.get(Item.class, new Long(1234));
tx.commit();
session.close(); // end of first session, item is detached
item.getId(); // The database identity is "1234"
item.setDescription("my new description");
Session session2 = sessionFactory.openSession();
Transaction tx2 = session2.beginTransaction();
Item item2 = (Item) session2.get(Item.class, new Long(1234));
Item item3 = session2.merge(item); // Success!
tx2.commit();
session2.close();
Es importante tener en cuenta que merge devuelve una referencia a la versión recién actualizada de la instancia. No es volver a colocar el elemento en la Sesión. Si prueba por ejemplo igualdad (ítem == ítem3), encontrará que devuelve falso en este caso. Probablemente querrás trabajar con item3 a partir de ahora.
También es importante tener en cuenta que Java Persistence API (JPA) no tiene un concepto de objetos separados y reacomodados, y utiliza EntityManager.persist () y EntityManager.merge ().
En general, he descubierto que al usar Hibernate, saveOrUpdate () suele ser suficiente para mis necesidades. Normalmente solo necesito usar merge cuando tengo objetos que pueden tener referencias a objetos del mismo tipo. Más recientemente, la causa de la excepción estaba en el código que validaba que la referencia no era recursiva. Estaba cargando el mismo objeto en mi sesión como parte de la validación, causando el error.
¿Dónde has encontrado este problema? ¿Fusionó trabajo para usted o necesitó otra solución? ¿Prefiere usar siempre la fusión, o prefiere usarla solo cuando sea necesario para casos específicos?
Ninguna de las siguientes respuestas es correcta. Todos estos métodos parecen ser iguales, pero en la práctica hacen cosas absolutamente diferentes. Es difícil dar pequeños comentarios. Es mejor proporcionar un enlace a la documentación completa sobre estos métodos: http://docs.jboss.org/hibernate/core/3.6/reference/en-US/html/objectstate.html
Tenga en cuenta que si llama a una actualización de un objeto separado, siempre habrá una actualización en la base de datos, ya sea que haya cambiado el objeto o no. Si no es lo que quieres, debes usar Session.lock () con LockMode.None.
Debe llamar a la actualización solo si el objeto fue cambiado fuera del alcance de su sesión actual (cuando está en modo separado).
╔══════════════╦═══════════════════════════════╦════════════════════════════════╗
║ METHOD ║ TRANSIENT ║ DETACHED ║
╠══════════════╬═══════════════════════════════╬════════════════════════════════╣
║ ║ sets id if doesn''t ║ sets new id even if object ║
║ save() ║ exist, persists to db, ║ already has it, persists ║
║ ║ returns attached object ║ to DB, returns attached object ║
╠══════════════╬═══════════════════════════════╬════════════════════════════════╣
║ ║ sets id on object ║ throws ║
║ persist() ║ persists object to DB ║ PersistenceException ║
║ ║ ║ ║
╠══════════════╬═══════════════════════════════╬════════════════════════════════╣
║ ║ ║ ║
║ update() ║ Exception ║ persists and reattaches ║
║ ║ ║ ║
╠══════════════╬═══════════════════════════════╬════════════════════════════════╣
║ ║ copy the state of object in ║ copy the state of obj in ║
║ merge() ║ DB, doesn''t attach it, ║ DB, doesn''t attach it, ║
║ ║ returns attached object ║ returns attached object ║
╠══════════════╬═══════════════════════════════╬════════════════════════════════╣
║ ║ ║ ║
║saveOrUpdate()║ as save() ║ as update() ║
║ ║ ║ ║
╚══════════════╩═══════════════════════════════╩════════════════════════════════╝
Consulte el Foro de Hibernate para obtener una explicación de las diferencias sutiles entre persistir y guardar. Parece que la diferencia es el momento en que se ejecuta finalmente la instrucción INSERT. Como save devuelve el identificador, la instrucción INSERT debe ejecutarse instantáneamente independientemente del estado de la transacción (lo que generalmente es algo malo). Persist no ejecutará ningún enunciado fuera de la transacción en ejecución solo para asignar el identificador. Save / Persist ambos funcionan en instancias transitorias , es decir, instancias que aún no tienen ningún identificador asignado y, como tales, no se guardan en el DB.
Update y Merge funcionan en instancias separadas , es decir, instancias que tienen una entrada correspondiente en el DB pero que actualmente no están asociadas (ni administradas por) una Session. La diferencia entre ellos es lo que sucede con la instancia que se pasa a la función. la actualización intenta volver a conectar la instancia, lo que significa que no puede haber otra instancia de la entidad persistente adjunta a la Sesión en este momento, de lo contrario se lanzará una excepción. merge , sin embargo, simplemente copia todos los valores a una instancia persistente en la sesión (que se cargará si no está cargada actualmente). El objeto de entrada no se cambia. Así que combinar es más general que la actualización , pero puede usar más recursos.