unidirectional onetomany one many inversejoincolumns intermediate example java hibernate jpa persistence openjpa

java - onetomany - one to many jpa hibernate



InserciĆ³n masiva de JPA/Hibernate(lote) (3)

Aquí hay un ejemplo simple que he creado después de leer varios temas sobre inserciones de jpa, tengo 2 objetos persistentes, Usuario y Sitio. Un usuario podría tener muchos sitios, por lo que tenemos una relación entre muchos aquí. Supongamos que quiero crear un usuario y crear / vincular varios sitios a la cuenta de usuario. Así es como se ve el código, considerando que estoy dispuesto a usar la inserción masiva para los objetos del Sitio.

User user = new User("John Doe"); user.getSites().add(new Site("google.com", user)); user.getSites().add(new Site("yahoo.com", user)); EntityTransaction tx = entityManager.getTransaction(); tx.begin(); entityManager.persist(user); tx.commit();

Pero cuando ejecuto este código (estoy usando hibernate como proveedor de implementación jpa) veo el siguiente resultado sql:

Hibernate: insert into User (id, name) values (null, ?) Hibernate: call identity() Hibernate: insert into Site (id, url, user_id) values (null, ?, ?) Hibernate: call identity() Hibernate: insert into Site (id, url, user_id) values (null, ?, ?) Hibernate: call identity()

Entonces, me refiero a que la inserción masiva "real" no funciona o estoy confundido.

Aquí está el código fuente para este proyecto de ejemplo, este es el proyecto de maven, por lo que solo tiene que descargar y ejecutar mvn install para verificar la salida.

ACTUALIZADO:

Después de que Ken Liu lo aconsejara amablemente, deshabilité la generación automática de ID de objetos del sitio:

User user = new User("John Doe"); user.getSites().add(new Site(1, "google.com", user)); user.getSites().add(new Site(2, "yahoo.com", user)); entityManager.setFlushMode(FlushModeType.COMMIT); EntityTransaction tx = entityManager.getTransaction(); tx.begin(); entityManager.persist(user); tx.commit();

Ahora tengo la siguiente línea en la salida de depuración:

DEPURACIÓN: org.hibernate.jdbc.AbstractBatcher - Ejecución de tamaño de lote: 2

¡Funciona!


He encontrado que es mucho más eficiente pasar por alto el hibernate para inserciones masivas. Debe eliminar ORM (asignación relacional de objetos) pero aún puede aprovechar la conexión asociada con la sesión actual y la gestión de transacciones.

Mientras pierde temporalmente la conveniencia de su ORM, el beneficio es significativo, especialmente si ha generado Ids de forma nativa ya que Hibernate normalmente realizaría un SELECT para cada INSERT .

Session.doWork es muy útil para facilitar esto.

private MyParentObject saveMyParentObject(final MyParentObject parent, final List<MyChildObject> children) { transaction = session.beginTransaction(); try { session.save(parent); // NOTE: parent.parentId assigned and returned here session.doWork(new Work() { public void execute(Connection con) throws SQLException { // hand written insert SQL - can''t use hibernate PreparedStatement st = con.prepareStatement("INSERT INTO my_child (parent_id, name, ...) values (?, ?, ...)"); for (MyChildObject child : children) { MyChildObject child = new MyChildObject(); child.setParentId(parent.getParentId()); // assign parent id for foreign key // hibernate can''t help, determine jdbc parameters manually st.setLong(1, child.getParentId()); st.setString(2, child.getName()); ... st.addBatch(); } // NOTE: you may want to limit the size of the batch st.executeBatch(); } }); // if your parent has a OneToMany relationship with child(s), refresh will populate this session.refresh(parent); transaction.commit(); return parent; } catch(Throwable e) { transaction.rollback(); throw new RuntimeException(e); } }



Si está utilizando la base de datos para generar identificadores, Hibernate debe ejecutar una consulta para generar la clave principal para cada entidad.