¿Cuáles son las diferencias entre los diferentes métodos de ahorro en Hibernate?


Hibernate tiene un puñado de métodos que, de una forma u otra, toma tu objeto y lo coloca en la base de datos. ¿Cuáles son las diferencias entre ellos, cuándo usar cuál, y por qué no hay un solo método inteligente que sepa cuándo usar qué?

Los métodos que he identificado hasta ahora son:

  • save()
  • update()
  • saveOrUpdate()
  • saveOrUpdateCopy()
  • merge()
  • persist()
Author: shA.t, 2008-10-02

8 answers

Aquí está mi comprensión de los métodos. Principalmente estos se basan en la API aunque como no uso todos estos en la práctica.

SaveOrUpdate Las llamadas se guardan o se actualizan dependiendo de algunas comprobaciones. Por ejemplo, si no existe ningún identificador, se llama a save. De lo contrario se llama update.

Guardar Persiste una entidad. Asignará un identificador si no existe. Si uno lo hace, esencialmente está haciendo una actualización. Devuelve el ID generado de la entidad.

Actualización Intenta mantener la entidad utilizando un identificador existente. Si no existe ningún identificador, creo que se lanza una excepción.

SaveOrUpdateCopy Esto está obsoleto y ya no debe usarse. En lugar de eso sí...

Merge Ahora aquí es donde mi conocimiento comienza a fallar. Lo importante aquí es la diferencia entre entidades transitorias, desapegadas y persistentes. Para obtener más información sobre los estados del objeto, eche un vistazo aquí. Con guardar y actualizar, está tratando con objetos persistentes. Están vinculados a una Sesión para que Hibernate sepa qué ha cambiado. Pero cuando tienes un objeto transitorio, no hay sesión involucrada. En estos casos, debe usar merge para las actualizaciones y persist para guardar.

Persist Como se mencionó anteriormente, esto se usa en objetos transitorios. No devuelve el ID generado.

 109
Author: Lee Theobald,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-02-18 20:10:15
╔══════════════╦═══════════════════════════════╦════════════════════════════════╗
║    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()         ║
║              ║                               ║                                ║
╚══════════════╩═══════════════════════════════╩════════════════════════════════╝
 111
Author: Sergii Shevchyk,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-09-03 20:30:57
  • Vea el Foro de Hibernación para una explicación de las sutiles diferencias entre persistir y guardar. Parece que la diferencia es el momento en que la instrucción INSERT se ejecuta en última instancia. Dado que 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á ninguna instrucción fuera de la transacción actualmente en ejecución solo para asignar identificador. Save / Persist ambos funcionan en instancias transitorias, es decir, instancias que no tienen identificador asignado todavía y, como tal, no se guardan en la base de datos.

  • Update y Merge ambos funcionan en instancias separadas, es decir, instancias que tienen una entrada correspondiente en la base de datos pero que actualmente no están asociadas a (o administradas por) una sesión. La diferencia entre ellos es lo que sucede con la instancia que se pasa a la función. actualización intenta volver a conectar la instancia, lo que significa que puede que no haya 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 mergees más general que update, pero puede usar más recursos.

 65
Author: jrudolph,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-10-02 09:05:00

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 poca frecuencia lo suficiente como para que cuando los veamos de nuevo, sepamos que hemos resuelto esto, pero no podemos recordar cómo.

La NonUniqueObjectException lanzada cuando se usa Session.saveOrUpdate() en Hibernate es una de las mías. Voy a añadir nuevas funcionalidades a una aplicación compleja. Todas mis pruebas unitarias funcionan fino. Luego, al probar la interfaz de usuario, al intentar guardar un objeto, empiezo a obtener una excepción con el mensaje "un objeto diferente con el mismo valor de identificador ya estaba asociado con la sesión."Aquí hay un ejemplo de código 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 entender la causa de esta excepción, es importante entender los objetos separados y lo que sucede cuando se llama a saveOrUpdate() (o simplemente update()) en un objeto separado.

Cuando cerramos un individuo Sesión de hibernación, los objetos persistentes con los que estamos trabajando están separados. Esto significa que los datos todavía están en la memoria de la aplicación, pero Hibernate ya no es responsable del seguimiento de los cambios en los objetos.

Si luego modificamos nuestro objeto separado y queremos actualizarlo, tenemos que volver a unir el objeto. Durante ese proceso de reaplicación, Hibernate comprobará si hay otras copias del mismo objeto. Si encuentra alguna, tiene que decirnos que no sabe cuál es la copia" real" es más. Tal vez se hicieron otros cambios en esas otras copias que esperamos que se guarden, pero Hibernate no sabe de ellas, porque no las estaba administrando en ese momento.

En lugar de guardar datos posiblemente malos, Hibernate nos informa sobre el problema a través de la NonUniqueObjectException.

Entonces, ¿qué debemos hacer? En Hibernate 3, tenemos merge () (en Hibernate 2, use saveOrUpdateCopy ()). Este método forzará a Hibernar para copiar cualquier cambio de otras instancias separadas en el instancia que desea guardar, y por lo tanto fusiona todos los cambios en la memoria antes de guardar.

        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 asociar el elemento a la sesión. Si prueba por ejemplo equality (item = = item3), encontrará que devuelve false en este caso. Probablemente querrá trabajar con item3 desde este punto en adelante.

También es importante tener en cuenta que la Java Persistence API (JPA) no tiene un concepto de objetos separados y reensamblados, y utiliza EntityManager.persist () y EntityManager.fusionar().

He encontrado en general que cuando se utiliza 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 del validación, causando el error.

¿Dónde has encontrado este problema? ¿La fusión funcionó para usted o necesitaba otra solución? ¿Prefiere usar siempre merge, o prefiere usarlo solo según sea necesario para casos específicos

 11
Author: HakunaMatata,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-10-15 13:02:50

En realidad la diferencia entre los métodos de hibernación save() y persist() depende de la clase de generador que estamos utilizando.

Si nuestra clase generator está asignada, entonces no hay diferencia entre los métodos save() y persist(). Porque generador 'asignado' significa, como programador tenemos que dar el valor de la clave primaria para guardar en la base de datos correcta [Espero que conozca este concepto de generadores ] En caso de otra clase de generador asignada, supongamos que si nuestro nombre de clase de generador es Incremento significa hibernate it self asignará el valor de id de clave primaria en la base de datos a la derecha [aparte del generador asignado, hibernate solo se usa para cuidar el valor de id de clave primaria recuerde ], por lo que en este caso si llamamos al método save() o persist(), entonces insertará el registro en la base de datos normalmente Pero escuchar la cosa es, save() método puede devolver ese valor id clave primaria que se genera por hibernación y podemos verlo por

long s = session.save(k);

En este mismo caso, persist() nunca dan ningún valor a la cliente.

 4
Author: Hari Krishna,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-04-11 08:07:41

He encontrado un buen ejemplo que muestra las diferencias entre todos los métodos hibernate save:

Http://www.journaldev.com/3481/hibernate-session-merge-vs-update-save-saveorupdate-persist-example

En resumen, según el enlace anterior:

Guardar()

  • Podemos invocar este método fuera de una transacción. Si usamos esto sin transacción y tenemos cascada entre entidades, entonces solo la entidad primaria se guarda a menos que vaciemos la sesion.
  • Por lo tanto, si hay otros objetos mapeados desde el objeto principal, se guardan en el momento de confirmar la transacción o cuando vaciamos la sesión.

Persistir()

  • Es similar a usar 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 mapeadas no se guardarán un;ess limpiamos la sesión.

  • Resultados en insertar o actualizar consultas basadas en los datos proporcionados. Si los datos están presentes en la base de datos, se ejecuta la consulta de actualización.

Actualizar()

  • Hibernate update debe usarse cuando sabemos que solo estamos actualizando la información de la entidad. Esta operación agrega el objeto entity al contexto persistente y los cambios posteriores se rastrean y guardan cuando la transacción es comprometido.
  • Por lo tanto, incluso después de llamar a update,si establecemos algún valor en la entidad, se actualizarán cuando se confirme la transacción.

Fusionar()

  • Hibernate merge se puede usar para actualizar valores existentes, sin embargo este método crea una copia del objeto entity pasado y lo devuelve. El objeto devuelto es parte del contexto persistente y se realiza un seguimiento de cualquier cambio, el objeto pasado no se realiza un seguimiento. Esta es la principal diferencia con merge() de todos los demás método.

También para ejemplos prácticos de todos estos, por favor consulte el enlace que mencioné anteriormente, muestra ejemplos de todos estos métodos diferentes.

 4
Author: OutOfMind,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-04-12 06:53:11

Tenga en cuenta que si llama a una actualización en un objeto separado, siempre habrá una actualización realizada 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.Ninguno.

Debe llamar a update solo si el objeto se cambió fuera del ámbito de su sesión actual (cuando está en modo separado).

 2
Author: bernardn,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-10-03 12:13:20

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 hacer comentarios breves. Es mejor dar 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

 1
Author: Anton Popovich,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-10-26 10:38:45