Saltar al contenido

¿Cómo hacer inserciones masivas (varias filas) con JpaRepository?

Después de tanto trabajar ya hallamos la respuesta de esta contratiempo que muchos los lectores de nuestro sitio presentan. Si tienes algún detalle que aportar no dejes de compartir tu información.

Solución:

Para obtener una inserción masiva con Sring Boot y Spring Data JPA, solo necesita dos cosas:

  1. establecer la opción spring.jpa.properties.hibernate.jdbc.batch_size al valor apropiado que necesita (por ejemplo: 20).

  2. utilizar saveAll() método de su repositorio con la lista de entidades preparadas para insertar.

El ejemplo de trabajo está aquí.

Con respecto a la transformación de la declaración de inserción en algo como esto:

INSERT INTO table VALUES (1, 2), (3, 4), (5, 6)

el tal está disponible en PostgreSQL: puede establecer la opción reWriteBatchedInserts para true en conexión jdbc string:

jdbc:postgresql://localhost:5432/db?reWriteBatchedInserts=true

entonces el controlador jdbc hará esta transformación.

Puede encontrar información adicional sobre el procesamiento por lotes aquí.

ACTUALIZADO

Proyecto de demostración en Kotlin: sb-kotlin-batch-insert-demo

ACTUALIZADO

Hibernate deshabilita el procesamiento por lotes de inserción en el nivel de JDBC de forma transparente si usa un IDENTITY generador de identificadores.

El problema subyacente es el siguiente código en SimpleJpaRepository:

@Transactional
public  S save(S entity) 
    if (entityInformation.isNew(entity)) 
        em.persist(entity);
        return entity;
     else 
        return em.merge(entity);
    

Además de la configuración de la propiedad del tamaño del lote, debe asegurarse de que las llamadas a la clase SimpleJpaRepository persistan y no se fusionen. Hay algunos enfoques para resolver esto: use un @Id generador que no consulta la secuencia, como

@Id
@GeneratedValue(generator = "uuid2")
@GenericGenerator(name = "uuid2", strategy = "uuid2")
var id: Long

O forzar la persistencia para tratar los registros como nuevos al hacer que su entidad implemente Persistable y anule el isNew() llamada

@Entity
class Thing implements Pesistable 
    var value: Int,
    @Id
    @GeneratedValue
    var id: Long = -1
    @Transient
    private boolean isNew = true;
    @PostPersist
    @PostLoad
    void markNotNew() 
        this.isNew = false;
    
    @Override
    boolean isNew() 
        return isNew;
    

O anular el save(List) y use el administrador de la entidad para llamar persist()

@Repository
public class ThingRepository extends SimpleJpaRepository 
    private EntityManager entityManager;
    public ThingRepository(EntityManager entityManager) 
        super(Thing.class, entityManager);
        this.entityManager=entityManager;
    

    @Transactional
    public List save(List things) 
        things.forEach(thing -> entityManager.persist(thing));
        return things;
    

El código anterior se basa en los siguientes enlaces:

  • http://www.hameister.org/SpringBootUsingIdsForBulkImports.html
  • http://www.hameister.org/SpringBootBulkImportWithCrudRepository.html
  • https://vladmihalcea.com/la-mejor-manera-de-hacer-procesamiento-por-lotes-con-jpa-e-hibernate/

Puede configurar Hibernate para hacer DML masivo. Eche un vistazo a Spring Data JPA: inserciones/actualizaciones masivas simultáneas. Creo que la sección 2 de la respuesta podría resolver su problema:

Habilite el procesamiento por lotes de declaraciones DML Habilitar el soporte de procesamiento por lotes daría como resultado una menor cantidad de viajes de ida y vuelta a la base de datos para insertar/actualizar la misma cantidad de registros.

Citando declaraciones INSERT y UPDATE por lotes:

hibernate.jdbc.batch_size = 50

hibernate.order_inserts = true

hibernate.order_updates= true

hibernate.jdbc.batch_versioned_data= true

ACTUALIZAR: Tienes que configurar las propiedades de hibernación de manera diferente en tu application.properties expediente. Están bajo el espacio de nombres: spring.jpa.properties.*. Un ejemplo podría verse como el siguiente:

spring.jpa.properties.hibernate.jdbc.batch_size = 50
spring.jpa.properties.hibernate.order_inserts = true
....

valoraciones y comentarios

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *