Lote APP portátil / Inserción masiva
Pregunta
Me salté en una función escrita por otra persona que parece un poco ineficiente, pero mi conocimiento de la APP no es tan bueno para encontrar una solución portátil que no está Hibernate específica.
En pocas palabras el método Dao llamada dentro de un bucle para insertar cada una de las nuevas entidades realiza una "EntityManager.merge (objeto);".
No queremos que existe una forma definida en las especificaciones de la APP para pasar una lista de entidades en el método Dao y hacer una inserción masiva / lote en lugar de llamar de mezcla para cada objeto?
Además, puesto que el método Dao se anota w / "@Transactional" Me pregunto si cada llamada de combinación única está sucediendo dentro de su propia transacción ... lo que no ayudaría rendimiento.
¿Alguna idea?
Solución
No hay ninguna operación de lote en JPA vainilla.
Sí, cada inserto se llevará a cabo dentro de su propia transacción. El atributo @Transactional
(sin calificadores) significa un nivel de propagación de REQUIRED
(crear una transacción si no existe ya). Asumiendo que tiene:
public class Dao {
@Transactional
public void insert(SomeEntity entity) {
...
}
}
hacer esto:
public class Batch {
private Dao dao;
@Transactional
public void insert(List<SomeEntity> entities) {
for (SomeEntity entity : entities) {
dao.insert(entity);
}
}
public void setDao(Dao dao) {
this.dao = dao;
}
}
De esta manera todo el grupo de insertos se envuelve en una sola transacción. Si estamos hablando de un gran número de inserciones es posible que desee dividirlo en grupos de 1.000, 10.000 o lo que funcione como una transacción no confirmada suficientemente grande puede morir de hambre la base de datos de los recursos y, posiblemente, fallar debido al tamaño solo.
Nota: @Transactional
es una anotación de primavera. Ver Gestión transaccional desde la primavera de referencia.
Otros consejos
Lo que podría hacer, si estuviera en un estado de ánimo astuto, es la siguiente:
@Entity
public class SomeEntityBatch {
@Id
@GeneratedValue
private int batchID;
@OneToMany(cascade = {PERSIST, MERGE})
private List<SomeEntity> entities;
public SomeEntityBatch(List<SomeEntity> entities) {
this.entities = entities;
}
}
List<SomeEntity> entitiesToPersist;
em.persist(new SomeEntityBatch(entitiesToPersist));
// remove the SomeEntityBatch object later
Debido a la cascada, que hará que las entidades a ser insertados en una sola operación.
Dudo que haya ninguna ventaja práctica para hacer esto una simple persistencia de objetos individuales en un bucle. Sería interesante analizar el SQL que la aplicación APP emitido, y para referencia.