简体   繁体   中英

How to manage transactions in spring boot

I have a spring boot application and use camel with it, I read a file and then I try to inserted on my DB, everything is working good the only problem is that I try to use @transactional or transactionTemplate to make a rollback when an error occur but it doesn't make the rollback,

With the @transactional I add to my SpringBootApplication the @EnableTransactionManagement(proxyTargetClass=true) and in my class I add the @Transactional(rollbackFor = Exception.class)

These are my classes:

@SpringBootApplication
@EnableDiscoveryClient
@EnableTransactionManagement(proxyTargetClass=true)
public class MsArchivo510Application {

    public static void main(String[] args) {
        SpringApplication.run(MsArchivo510Application.class, args);
    }
}

@Service
public class ArchivoBS implements Processor{
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void process(Exchange exchange) throws Exception {
        //Here I execute stored procedure and one of them fail
    }
}

With the transactioTemplate my class end up like this:

@Service
public class ArchivoBS implements Processor{
    @Override
    public void process(Exchange exchange) throws Exception {

        transactionTemplate.execute(new TransactionCallbackWithoutResult() {

            @Override
            protected void doInTransactionWithoutResult(TransactionStatus status) {
            try {
                //Here I execute stored procedure and one of them fail
            } catch (Exception e) {
                e.printStackTrace();
                status.setRollbackOnly();
            }
        }
       });
    }
}

Am I missing something?, Can someone help me with this issue?,

Thanks in advance

You're in a camel context and Spring-boot may have difficulties to work properly. You could try to make your transaction operation in a spring service and inject it in you processor then add @Transaction on your service method and call it from your processor.

At the end I noticed that I need to specify to my data source the DataSourceTransactionManager, I have a class with the annotation @Configuration and there I can create multiples data source, so my class were like this:

@Configuration
public class Configuracion {

    @Bean(name = "mysqlNocturno")
    @ConfigurationProperties(prefix = "spring.nocturno")
    public DataSource mysqlDataSourceNocturno() {
        return DataSourceBuilder.create().build();
    }

    @Bean(name = "jdbcTemplateNocturno")
    public JdbcTemplate jdbcTemplateNocturno(@Qualifier("mysqlNocturno") DataSource dsMySQL) {
        return new JdbcTemplate(dsMySQL);
    }

    @Bean(name = "mysqlProduccion")
    @Primary
    @ConfigurationProperties(prefix = "spring.produccion")
    public DataSource mysqlDataSourceProduccion() {
        return  DataSourceBuilder.create().build();
    }

    @Bean(name = "jdbcTemplateProduccion")
    public JdbcTemplate jdbcTemplateProduccion(@Qualifier("mysqlProduccion") DataSource dsMySQL) {
        return new JdbcTemplate(dsMySQL);
    }

}

The documentation mention that the annotation @EnableTransactionManagement need to be added on my SpringBootApplication class but that is not necessary, it need to be added on my configuration class, so my class end up like this:

@Configuration
@EnableTransactionManagement
public class Configuracion {

    @Bean(name = "mysqlNocturno")
    @ConfigurationProperties(prefix = "spring.nocturno")
    public DataSource mysqlDataSourceNocturno() {
        return DataSourceBuilder.create().build();
    }

    @Bean(name = "jdbcTemplateNocturno")
    public JdbcTemplate jdbcTemplateNocturno(@Qualifier("mysqlNocturno") DataSource dsMySQL) {
        return new JdbcTemplate(dsMySQL);
    }

    @Bean(name = "transactionManagerNocturno")
    public PlatformTransactionManager transactionManagerNocturno() {
        return new DataSourceTransactionManager(mysqlDataSourceNocturno());
    }

    @Bean(name = "mysqlProduccion")
    @Primary
    @ConfigurationProperties(prefix = "spring.produccion")
    public DataSource mysqlDataSourceProduccion() {
        return  DataSourceBuilder.create().build();
    }

    @Bean(name = "jdbcTemplateProduccion")
    public JdbcTemplate jdbcTemplateProduccion(@Qualifier("mysqlProduccion") DataSource dsMySQL) {
        return new JdbcTemplate(dsMySQL);
    }

    @Bean(name = "transactionManagerProduccion")
    public PlatformTransactionManager transactionManagerProduccion() {
        return new DataSourceTransactionManager(mysqlDataSourceProduccion());
    }

}

With this configuration I only need to add the @transactional annotation to my class like @Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class)

@Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class) 
@Override
public void altaArchivo(Mensaje objMensaje, ArchivoCarnet objArchivoCarnet, ArchivoCarnetTrailer objArchivoCarnetTrailer, List<ArchivoCarnetDetalle> lstArchivoCarnetDetalle) {

    if (objMensaje.getStrCodigo().equals(ArchivoErrorEnum.OPERACION_EXITOSA.getStrCodigo())) {
        archivoDAO.altaArchivoCarnet(objArchivoCarnet);
        archivoDAO.altaArchivoCarnetTrailer(objArchivoCarnetTrailer);
        archivoDAO.altaArchivoCarnetDetalle(lstArchivoCarnetDetalle);
    } else {
        archivoDAO.altaBitacoraArchivo510(new BitacoraArchivo510(objMensaje, objArchivoCarnet.getStrNombre()));
    }

}

Hope this help someone else :)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM