es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

La transacción anidada en la tarea SpringBatch no funciona.

Estoy usando SpringBatch para mi aplicación. En uno de los trabajos por lotes, necesito procesar varios datos. Cada dato requiere varias actualizaciones en la base de datos. Y necesito hacer una transacción por cada dato. Es decir, si al procesar un dato se produce una excepción, las actualizaciones de la base de datos se deshacen para ese dato y luego se continúa procesando el siguiente dato.

He colocado todas las actualizaciones de la base de datos en un método en la capa de servicio. En mi tarea de SpringBatch, llamo a ese método para cada dato, de esta manera;

for (RequestViewForBatch request : requestList) {
  orderService.processEachRequest(request);
}

En la clase de servicio, el método se ve así;

@Transactional(propagation = Propagation.NESTED, timeout = 100, rollbackFor = Exception.class)
public void processEachRequest(RequestViewForBatch request) {
  // actualización de la base de datos
}

Al ejecutar la tarea, me muestra este mensaje de error:

org.springframework.transaction.NestedTransactionNotSupportedException: Transaction manager does not allow nested transactions by default - specify 'nestedTransactionAllowed' property with value 'true'

pero no sé cómo solucionar este error.

Cualquier sugerencia sería apreciada. Gracias de antemano.

Tags:  , ,

Answer

  1. Avatar for davy.ai

    El mensaje de error sugiere que el administrador de transacciones no permite transacciones anidadas de forma predeterminada. Para resolver el error, puedes intentar configurar la propiedad nestedTransactionAllowed del administrador de transacciones en true.
    Esto se puede hacer en el archivo de configuración de tu aplicación agregando las siguientes líneas:

    spring:
      jpa:
        properties:
          hibernate.transaction.coordinator.allow_jta_transaction_completion: true
          hibernate.transaction.coordinator.allow_transaction_outside_join: true
          hibernate.transaction.factory_class: org.hibernate.transaction.JTATransactionFactory
      datasource:
        url: jdbc:mysql://localhost:3306/mydatabase
        username: root
        password: password
        driver-class-name: com.mysql.jdbc.Driver
      jta:
        transactionManager: com.atomikos.icatch.jta.UserTransactionManager
        userTransaction: com.atomikos.icatch.jta.UserTransactionImp
    

    donde com.atomikos.icatch.jta.UserTransactionManager y com.atomikos.icatch.jta.UserTransactionImp son clases proporcionadas por Atomikos, una biblioteca de terceros que se puede utilizar como administrador de transacciones JTA para proyectos de Spring.
    Alternativamente, puedes intentar cambiar el atributo propagation de la anotación @Transactional a Propagation.REQUIRES_NEW, que crea una nueva transacción para cada invocación del método anotado.

    @Transactional(propagation = Propagation.REQUIRES_NEW, timeout = 100, rollbackFor = Exception.class)
      public void processEachRequest(RequestViewForBatch request) {
    //update database
    }
    

    Esto debería permitirte realizar múltiples actualizaciones de base de datos dentro de un trabajo por lotes, con cada actualización siendo cancelada de forma independiente en caso de una excepción.

Comments are closed.