Este artículo describe el método de operación por lotes de hibernación. Compártelo para su referencia, como sigue:
Procesamiento por lotes de hibernación
Hibernate opera la base de datos completamente de forma orientada a objetos. Cuando un objeto persistente se opera de manera orientada a objetos en el programa, se convertirá automáticamente en una operación en la base de datos. Por ejemplo, cuando llame al método Delete () de Session para eliminar un objeto persistente, Hibernate será responsable de eliminar los registros de datos correspondientes; Al ejecutar el método establecido del objeto persistente, Hibernate se convertirá automáticamente al método de actualización correspondiente y modificará los registros correspondientes de la base de datos.
La pregunta es si se deben actualizar 100,000 registros al mismo tiempo, ¿necesita cargar 100,000 registros uno por uno y luego llamar al método establecido a su vez? Esto no solo es engorroso, sino que también el rendimiento del acceso a los datos es muy malo. Para este escenario de procesamiento por lotes, Hibernate proporciona una solución de procesamiento por lotes. Lo siguiente presenta cómo enfrentar esta situación de procesamiento por lotes desde tres aspectos: inserción por lotes, actualización por lotes y eliminación de lotes.
1 inserción por lotes
Si necesita insertar 100,000 registros en la base de datos, Hibernate generalmente puede usar lo siguiente:
Sesión session = sessionFactory.opensession (); transacción tx = session.begintransaction (); for (int i = 0; i <100000; i ++) {user u = new user (......); session.save (cliente);} tx.commit (); session.close ();Pero a medida que se ejecuta este programa, siempre fallará en algún momento y se lanza una OutOfMemoryException. Esto se debe a que la sesión de Hibernate tiene un caché de nivel 1 requerido, y todas las instancias de usuario se almacenarán en caché en el área de caché a nivel de sesión.
Para resolver este problema, hay una idea muy simple: actualice regularmente los datos almacenados en caché por la sesión en la base de datos, en lugar de almacenarlo en caché en el nivel de sesión. Puede considerar diseñar un acumulador, que aumenta en 1 para cada instancia de usuario guardada. Determine si los datos en la memoria caché de la sesión deben enjuagarse en la base de datos en función del valor del acumulador.
Aquí hay un fragmento de código que agrega 100,000 instancias de usuario:
Private void testUser () lanza la excepción {// Abrir sesión de sesión Session = HibernateUtil.CurrentSession (); // Iniciar transacción transacción tx = session.begintransaction (); // bucle 100 000 veces e inserta 100 000 registros para (int i = 0; i <1000000; i ++) {// Crear user User User U1 = New User (); U1.setName ("xxxxx" + i); U1.setage (i); U1.setnacionalidad ("China"); // Cach la instancia de usuario session.save (u1); // Cada vez que el acumulador es un múltiplo de 20, enjuague los datos en la sesión en la base de datos y borre el caché de la sesión si (i % 20 == 0) {session.flush (); session.clear (); tx.commit (); tx = session.beGinTransaction (); }} // Conjunto de transacción tx.commit (); // Cerrar transacción hibernateUtil.Clossessession ();}En el código anterior, cuando i%20 == 0, los datos en caché en la sesión se escriben manualmente en la base de datos y la transacción se envía manualmente. Si no se envía la transacción, los datos aún se almacenarán en caché en la oficina de transacciones; no ha ingresado la base de datos, lo que también causará una excepción del desbordamiento de la memoria.
Este es el procesamiento de la memoria caché de nivel de sesión, y el caché secundario de SessionFactory también debe desactivarse a través de la siguiente configuración.
hibernate.cache.use_second_level_cache falso
Nota: Además de borrar manualmente el caché a nivel de sesión, es mejor desactivar el caché secundario de nivel de sesión de sesión. De lo contrario, incluso si el caché de nivel de sesión se borra manualmente, se puede lanzar una excepción porque todavía hay un caché en el nivel de SessionFactory.
2 actualizaciones de lotes
El método descrito anteriormente también es adecuado para datos de actualización por lotes. Si necesita devolver varias filas de datos, puede usar el método Scroll () para hacer un uso completo de las ventajas de rendimiento traídas por los cursores del lado del servidor. Aquí hay un fragmento de código para actualizaciones por lotes:
Private void testUser () lanza la excepción {// Abrir sesión de sesión Session = HibernateUtil.CurrentSession (); // Iniciar la transacción de la transacción tx = session.begintransaction (); // consulta todos los registros en la tabla de usuario scrollableReSults users = session.createQuery ("del usuario") .setCachemode (cachemode.ignore) .scroll (scrollmode.forward_only); int count = 0; // Transacción Todos los registros en la tabla de usuarios mientras (ussers.next ()) {user u = (user) uss.get (0); U.SetName ("nuevo nombre de usuario" + Count); // Cuando el recuento es un múltiplo de 20, enjuague el resultado actualizado de la sesión a la base de datos si (++ count % 20 == 0) {session.flush (); session.clear (); }} tx.commit (); Hibernateutil.clossesession ();} De esta manera, aunque se pueden realizar actualizaciones por lotes, el efecto es muy pobre. La eficiencia de ejecución no es alta, y se requiere primero la consulta de datos, y luego se realiza la actualización de datos. Esta actualización será una actualización de fila por línea, es decir, cada vez que se actualice una fila de registros, se debe ejecutar una declaración de actualización y el rendimiento es muy bajo.
Para evitar esto, Hibernate proporciona una sintaxis HQL similar a SQL para actualizaciones por lotes y eliminación de lotes.
Actualización/eliminación de 3 lotes de estilo SQL
Las declaraciones HQL proporcionadas por Hibernate también admiten la actualización de lotes y eliminar la sintaxis.
El formato de sintaxis de las declaraciones de actualización y eliminación de lotes es el siguiente:
Actualización | Eliminar de? ClassName [Where Where_conditions]
Hay cuatro puntos que vale la pena señalar sobre el formato de sintaxis anterior:
● En la cláusula FROM, la palabra clave desde es opcional. Es decir, no puede escribir de palabras clave en absoluto.
● Solo puede haber un nombre de clase en la cláusula FROM, y el nombre de la clase no puede tener un alias.
● No puede usar conexiones en declaraciones HQL por lotes, ni explícitas ni implícitas. Pero las subconsules se pueden usar en la cláusula WHERE.
● Toda la cláusula Where es opcional.
Suponiendo que necesita cambiar el atributo de nombre de la instancia de clase de usuario, puede usar el siguiente fragmento de código:
Private void testUser () lanza la excepción {// Abrir sesión de sesión Session = HibernateUtil.CurrentSession (); // Iniciar transacción transacción tx = session.begintransaction (); // Definir la actualización de la instrucción HQL HQLUPDATE = "Actualizar el nombre del usuario Nombre =: Newname"; // Ejecutar Update int UpdateatedEnties = session.CreateQuery (hqlupdate) .setString ("Newname", "New Name") .ExCuteUpdate (); // Conjunto de transacción tx.commit (); Hibernateutil.clossesession ();}Como se puede ver en el código anterior, esta sintaxis es muy similar a la sintaxis EjecutarUpdate de preparada. De hecho, esta actualización por lotes de HQL está tomando prestado directamente de la declaración de actualización de la sintaxis SQL.
Nota: Al usar esta sintaxis de actualización por lotes, generalmente solo necesita ejecutar la instrucción de actualización SQL una vez para completar todas las actualizaciones que cumplan con los registros condicionales. Pero también puede ser necesario ejecutar múltiples declaraciones de actualización, porque hay casos especiales como el mapeo de herencia, como hay una instancia de persona, que tiene una instancia de subclase del cliente. Cuando Batch actualiza las instancias de la persona, la instancia del cliente también debe actualizarse. Si usa la estrategia de mapeo de sucripción unida o de sucripción sindical, las instancias de persona y clientes se guardan en diferentes tablas, por lo que pueden ser necesarias declaraciones de actualización múltiple.
Ejecute un HQL Delete y use el método Query.executeUpdate (). El siguiente es un fragmento de código que elimina todos los registros anteriores a la vez:
Private void testUser () lanza la excepción {// Abrir sesión de sesión de sesión Session = HibernateUtil.CurrentSession (); // Iniciar transacción transacción tx = session.begintransaction (); // Definir la deleción de lotes HQL Declaración String hqlupdate = "Eliminar usuario"; // Ejecutar la eliminación de lotes int UpdateatedEntities = session.CreateQuery (HQLUPDATE) .ExCuteUpdate (); // Conjunto de transacción tx.commit (); // Cerrar sesión hibernateUtil.clossessession ();}Devuelve un valor entero mediante el método Query.ExecuteUpdate (), que es el número de registros afectados por esta operación. De hecho, las operaciones subyacentes de Hibernate se realizan a través de JDBC. Por lo tanto, si hay lotes de operaciones de actualización o eliminación que se convierten en declaraciones de actualización o eliminación múltiples, el método devuelve el número de registros afectados por la última declaración SQL.
Espero que la descripción en este artículo sea útil para la programación Java de todos en función del marco Hibernate.