Hacer que Hibernate haga actualizaciones simples, en lugar de una enorme selección y actualizaciones
-
06-07-2019 - |
Pregunta
Vamos a configurar la pregunta primero.
Lo que tengo son > 4 tablas: Cliente, Dirección, Pedido, Artículos de pedido. Cada uno se asigna mediante Anotaciones de Hibernate y se accede a través de una capa Spring DAO / Services.
Lo que intento hacer es fusionar clientes duplicados. Entonces, todo lo que realmente necesita suceder es que todos los pedidos y direcciones asociados con el cliente B, necesiten actualizar su clave externa customer_id para apuntar al cliente A. Luego, el cliente B debe tener su bit deshabilitado establecido.
En lugar de enviar estas consultas simples a nuestra base de datos, hibernate se vuelve loco y emite una tonelada de consultas de selección y actualización. En particular, selecciona todos los artículos de pedido adjuntos a un pedido (porque esto se define EAGER
y este punto no se puede cambiar). Para obtener las selecciones antes de que la actualización deje de suceder, intenté agregar la anotación de entidad de hibernación en la parte superior del javax.persistence.Entity
normal como:
@org.hibernate.annotations.Entity(dynamicUpdate = true, selectBeforeUpdate = false, dynamicInsert = true)
esto parecía no tener ningún efecto, excepto con consultas simples donde solo actualizaba elementos individuales en una tabla.
Obtengo los objetos usando los siguientes criterios de hibernación:
Criteria c1 = null;
Criteria c2 = null;
Criteria c = session.createCriteria(Customer.class);
c.setResultTransformer(CriteriaSpecification.DISTINCT_ROOT_ENTITY);
if(resultLimit>0) c.setMaxResults(resultLimit);
if(timeout>0) c.setTimeout(timeout);
for(String filter: sqlFilters) {
if(filter.indexOf("{alias}.customer_")!=-1) c.add(Restrictions.sqlRestriction(filter));
else if(filter.indexOf("{alias}.address_")!=-1 && addrsAttached) {
if(c1==null)
c1 = c.createCriteria("addresses").setFetchMode("type", FetchMode.JOIN);
c1.add(Restrictions.sqlRestriction(filter));
} else if(filter.indexOf("{alias}.order_")!=-1 && ordersAttached) {
if(c2==null)
c2 = c.createCriteria("orders").setFetchMode("orderItems", FetchMode.SELECT);
c2.add(Restrictions.sqlRestriction(filter));
}
}
return (List<Customer>) c.list();
Luego muevo todas las direcciones y objetos de pedido del cliente B al cliente A y ejecuto un
return (Customer) this.getHibernateTemplate().merge(customer);
en ambos objetos del cliente. Esto termina creando un montón de sentencias select que obtienen todos los objetos asociados (es decir, Artículos de pedido, Productos, Tipo de producto, ProductPricingTmpl, etc.)
¡Necesito eliminar estas selecciones! Si no estuvieran allí, la consulta se vería normal y sería eficiente. Las consultas actualizadas de salida son perfectas y dinámicas.
¿Alguna idea?
Solución
La pista podría estar en su elección de operación merge (). Del javadoc Hibernate:
Copia el estado del objeto dado en el objeto persistente con el mismo identificador Si no hay instancia persistente actualmente asociado con la sesión, lo hará ser cargado.
Entonces, estás obligando a Hibernate a cargar todos los datos antes de modificarlos.
Pruebe una operación diferente, como update ():
Actualice la instancia persistente con el identificador del dado separado instancia.
Sin embargo, sin promesas, Hibernate podría decidir que necesita cargarlo de todos modos. La configuración dynamicUpdates = true podría empeorarla, ya que necesita saber qué hay para comenzar antes de poder emitir actualizaciones dinámicas.