Quiero ejecutar varias instrucciones de actualización en la misma consulta en modo de hibernación Hql.
como a continuación:

hql = " update Table1 set prob1=null where id=:id1; "
                + " delete from Table2 where id =:id2 ";
...
query.executeUpdate();

en el mismo executeUpdate llamada que desea actualizar los registros de la Tabla1 y eliminar registros de la Tabla2.

Es posible?

si la relación entre las tablas y los datos que desea modificar permitir esta declaración, es posible, pero en mi humilde opinión, usted debe usar el modo de Hibernación Criteria en lugar de hql idioma. stackoverflow.com/questions/197474/…
Puedo ejecutar la instrucción en SQL estándar. Pero hibernate lanza la excepción unexpected char: ';'. Hibernate no es capaz de analizar la cadena correctamente. Me pregunto si hay otra sintaxis para la declaración o de otra manera utilizar HQL.
necesitarás varios Query::executeUpdate, no puede concatenar, pero será la misma transacción en la sesión
Como he dicho en mi respuesta, esto no es posible con HQL, debido a que Hibernate utiliza PreparedStatements para este.
A continuación, la respuesta es simplemente No. Si usted va a realizar múltiples actualización masiva como esta, hacerlo bajo Hibernate rara vez es una buena elección. ¿Por qué no hacerlo a través de JDBC puro, entonces? Y, si usted está haciendo la actualización masiva como esta, DB (ida y vuelta rara vez es el cuello de botella (a menos que usted está haciendo actualizar/eliminar por entidad, por lo que se deberá hacer por cambiar el estado de entidad/sesión.delete(), y dejar de Hibernación problema de detectar los cambios y el tema de la SQLs en lotes)

OriginalEl autor Nebras | 2016-08-19

5 Comentarios

  1. 2

    En definitiva, lo que están buscando es algo así como el procesamiento por lotes en JDBC. Thich no es de Hibernate para la Actualización Masiva de consulta, y dudo si es que alguna vez será considerado para la Hibernación.

    De mi experiencia en el pasado, los Lotes cuentan para HQL rara vez es útil en la vida real. Puede sonar extraño que algo sea útil en SQL+JDBC, pero no en HQL. Voy a tratar de explicar.

    Por lo general, cuando trabajamos con Hibernate (u otro similar ORM), trabajamos en contra de las entidades. Hibernate será el encargado de sincronizar nuestros entidades del estado con DB, que es la mayoría de los casos que JDBC procesamiento por lotes puede ayudar a mejorar el rendimiento. Sin embargo, en modo de Hibernación no cambiamos individuales de la entidad estatal por mayor consulta de Actualización.

    Simplemente dar un ejemplo, en pseudo-código:

    En JDBC, puede hacer algo como (estoy tratando de imitar lo que se muestra en el ejemplo):

    List<Order> orders = findOrderByUserId(userName);
    for (Order order: orders) {
        if (order outstanding quantity is 0) {
            dbConn.addBatch("update ORDER set STATE='C' where ID=:id", order.id);
        } else if (order is after expriation time) {
            dbConn.addBatch("delete ORDER where ID=:id", order.id);
        }
    }
    dbConn.executeBatch();

    Ingenuo traducción de JDBC lógica de Hibernación puede dar algo como esto:

    List<Order> orders = findOrderByUserId(userName);
    for (Order order: orders) {
        if (order outstanding quantity is 0) {
            q = session.createQuery("update Order set state='C' where id=:id");
            q.setParameter("id", order.id);
            q.executeUpdate();
        } else if (order is after expriation time) {
            q = session.createQuery("delete Order where id=:id");
            q.setParameter("id", order.id);
            q.executeUpdate();
        }
    }

    Sospecho que usted piensa que necesita el procesamiento por lotes característica porque estás haciendo algo similar (en base a su ejemplo, que el uso de actualización masiva para el registro individual). Sin embargo es NO cómo esto debe ser hecho en Hibernate/JPA

    (En realidad es mejor para envolver la persistencia de la capa de acceso a través de un repositorio, aquí estoy sólo la simplificación de la imagen)

    List<Order> orders = findOrderByUserId(userName);
    for (Order order: orders) {
        if (order.anyOutstanding()) {
            order.complete();    //which internally update the state
        } else if (order.expired) {
            session.delete(order);
        }
    }
    
    session.flush();   //or you may simply leave it to flush automatically before txn commit

    Al hacerlo, Hibernate es lo suficientemente inteligente como para detectar modificado/eliminado/inserta entidades, y hacer uso de JDBC lote para hacer la base de datos de la COALICIÓN de operaciones en flush(). Más importante, este es el propósito para el ORM: queremos proporcionar comportamiento ricos en las entidades de trabajo, por lo cual el estado interno de cambio de las entidades pueden ser «transparente» que se reflejan en el almacenamiento persistente.

    HQL Actualización Masiva objetivos para otro uso, que es algo así como una actualización masiva a DB a afectar a una gran cantidad de registros, por ejemplo:

    q = session.createQuery("update Order set state='C' " 
                            + " where user.id=:user_id "
                            + " and outstandingQty = 0 and state != 'C' ");
    q.setParameter("user_id", userId);
    q.executeUpdate();

    Rara vez hay una necesidad de la ejecución de una gran cantidad de consultas en este tipo de escenario de uso, por tanto, la sobrecarga de DB de ida es insignificante, y por lo tanto, el beneficio y el procesamiento por lotes de apoyo para la actualización masiva de consulta rara vez es significativo.

    No puedo omitir que hay casos en que usted realmente necesita para emitir una gran cantidad de consultas de actualización que no es apropiado para ser realizadas por la entidad comportamiento. En tal caso, usted puede desear reconsiderar si la Hibernación es el instrumento adecuado para ser utilizado. Usted puede considerar el uso de JDBC puro en tal caso de uso, de modo que usted tiene control sobre cómo se ejecutan consultas.

    Interesado en la razón de downvote 🙂

    OriginalEl autor Adrian Shum

  2. 4

    en el mismo executeUpdate llamada que desea actualizar los registros de la Tabla1 y
    eliminar registros de la Tabla2.

    Es posible?

    executeUpdate() ejecuta una sola consulta de actualización.
    Así que, no, usted no puede hacerlo. Usted tiene que ejecutar como muchas de las consultas de actualización de las tablas de actualizar/eliminar.
    Además, tiene un código más limpio si consultas por separado :

    • las consultas son más fáciles de leer y ajuste de los parámetros es legible y no propenso a errores.
    • para depurar la ejecución de la consulta, sería más fácil de entender si las consultas son manejados uno por uno en su propio executeUpdate()

    No significa que las consultas deben obligatorio ser trasmitida uno por uno.

    El Procesamiento por lotes es una característica de Hibernate para mejorar el rendimiento cuando se desea ejecutar múltiples consultas. Tienes que habilitar la característica de utilizar.
    hibernate.jdbc.batch_size propiedad debe ser configurado con un valor adecuado.

    Si están llevando a cabo el procesamiento por lotes, usted tendrá que activar el
    el uso de JDBC de procesamiento por lotes. Esto es absolutamente esencial si usted desea
    lograr un rendimiento óptimo. Establecer el JDBC tamaño de lote de un plazo razonable
    número (de 10 a 50, por ejemplo):

    de hibernación.jdbc.batch_size 20 de Hibernación desactiva la inserción de lotes en el
    JDBC nivel de forma transparente si utiliza un identificador de identidad generador.

    Además de la documentación oficial :

    Hibernate desactiva la inserción de lotes en el JDBC nivel de forma transparente si
    utilice una identidad identificador del generador.

    Sin embargo, en su caso, será inútil porque como Dragan Bozanovic explicó actualizar/eliminar tablas diferentes en sus consultas. Así, se podría crear como muchos de los lotes de las ejecuciones como tablas consultados.

    Así que, usted debe ejecutar cada consulta individual. Sólo commit() la transacción cuando se considere que debe ser :

    hql = "update Table1 set prob1=null where id=:id1;"
    ...
    query.setParameter("id1",...);
    query.executeUpdate();
    hql = "delete from Table2 where id =:id2";
    ...
    query.executeUpdate();
    query.setParameter("id2",...);
    ..
    tx.commit();
    No es un procesamiento por lotes. No seas tan agresivo, por favor.

    OriginalEl autor davidxxx

  3. 3

    No, no es posible, debido a que Hibernate utilizaPreparedStatements de esto (lo cual es bueno porque de bind variables), y PreparedStatements no admite lotes que consta de múltiples declaraciones diferentes.

    PreparedStatement sólo puede lotes de diferentes combinaciones de las variables vinculadas por una declaración, en la que Hibernate utiliza para lote de inserciones y actualizaciones al purgar los cambios en el contexto de persistencia (sesión).

    OriginalEl autor Dragan Bozanovic

  4. 1

    El SQL generado por JPA granel actualizaciones o eliminaciones, es decir, las llamadas a javax.la persistencia.Consulta.executeUpdate() no pueden ser procesadas por lotes por Hibernate cuando pasa a través de JDBC. @DraganBozanovic y @AdrianShum ya hemos explicado esto, pero para añadir a sus comentarios: executeUpdate() devuelve un entero (int, el número de entidades actualizado o eliminado) – independientemente de lavado de la sesión de Hibernate, ¿cómo podría el int ser devueltos sin llamar a la base de datos inmediatamente y de forma sincrónica? El JPQL/HQL/SQL tendría que ser evaluado en el lado del cliente, lo cual no es posible debido a las entidades a ser masiva, actualiza, elimina puede que ni siquiera se han leído en la sesión de Hibernate. Además si el update o delete no fueron ejecutados en la base de datos de inmediato, las consultas posteriores a leer en entidades JPA podría obtener datos obsoletos. Ejemplo:

    1. executeUpdate a granel eliminar a todos los Clientes con ID > 1000.
    2. leer entidad de Cliente con ID = 1001.

    Si el executeUpdate en 1 permitió ser aplazado hasta después de la lectura de a 2, luego de obtener la respuesta incorrecta (el Cliente todavía existe).

    Usted necesita leer las entidades en el uso de JPA, actualización de ellos, y dejar de Hibernación generar la actualización de SQL (que se puede batch), o llame a JDBC directamente para realizar las actualizaciones por lotes.

    OriginalEl autor coder

  5. 0

    ¿Por qué no ejecutar las dos consultas por separado en una Transaccional método

    Al anotar el método con @Transactional, si la consulta falla, el otro no se ejecutará.

     @Transactional(propagation = Propagation.REQUIRED, readOnly = false)
    
     public void executeQuery(Obj1 obj1) {
    
     String query="update table1 set actualRepaymentAmount=expectedRepaymentAmount,active='Y'  where loanCaseId = '"+caseId+"'";
            sessionFactory.getCurrentSession().createQuery(query).executeUpdate();
    
     query="update table2 set loanStatus='C' where loanCaseId = '"+caseId+"'";  
        sessionFactory.getCurrentSession().createQuery(query).executeUpdate();
    
            ...
    
     }
    La apertura de la transacción para cada lote no es muy eficaz.
    Yo ya uso un AOP en un alto nivel de llamada de servicio para la gestión de transacciones.

    OriginalEl autor Olakunle Awotunbo

Dejar respuesta

Please enter your comment!
Please enter your name here