0

I have a spring boot application that connects on two databases (oracle and sql server), but my @Transactional method commits the transaction before returning to the caller. I launch my app in debug mode and realized that just after calling the .save() method, the SQLServer table already had populated.

This only happen with SQLServer tables, with oracle the tables are filled after @Transactional method returning to the caller.

I have the following configuration classes:


@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
  basePackages = "br.com.getnet.consumerformalizada.repository.mssql",
  entityManagerFactoryRef = "mssqlEntityManagerFactory",
  transactionManagerRef = "mssqlTransactionManager" 
)
public class MsSqlDataSourceConfiguration {
    
    @Bean
    @ConfigurationProperties("spring.datasource.mssql")
    public DataSourceProperties mssqlDataSourceProperties() {
        return new DataSourceProperties();
    }
    
    @Bean
    public DataSource mssqlDataSource() {
        return mssqlDataSourceProperties()
                .initializeDataSourceBuilder()
                .build();
    }   
    
    @Bean
    public LocalContainerEntityManagerFactoryBean mssqlEntityManagerFactory(
      @Qualifier("mssqlDataSource") DataSource dataSource,
      EntityManagerFactoryBuilder builder) {
        return builder
          .dataSource(dataSource)
          .packages("br.com.getnet.consumerformalizada.model.mssql")
          .build();
    }

    @Bean
    public PlatformTransactionManager mssqlTransactionManager(
      @Qualifier("mssqlEntityManagerFactory") 
      LocalContainerEntityManagerFactoryBean mssqlEntityManagerFactory) {
        return new JpaTransactionManager(
                Objects.requireNonNull(mssqlEntityManagerFactory.getObject()));
    }

}



@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
  basePackages = {"br.com.getnet.consumerformalizada.repository.oracle"},
  entityManagerFactoryRef = "oracleEntityManagerFactory",
  transactionManagerRef = "oracleTransactionManager"
)
public class OracleDataSourceConfiguration {
    
    @Bean
    @Primary
    @ConfigurationProperties("spring.datasource.oracle")
    public DataSourceProperties oracleDataSourceProperties() {
        return new DataSourceProperties();
    }
    
    @Bean
    @Primary
    public DataSource oracleDataSource() {
        return oracleDataSourceProperties()
               .initializeDataSourceBuilder().build();              
    }
    
    @Bean
    @Primary
    public LocalContainerEntityManagerFactoryBean oracleEntityManagerFactory(
      @Qualifier("oracleDataSource") DataSource dataSource,
      EntityManagerFactoryBuilder builder) {
        return builder
          .dataSource(dataSource)
          .packages("br.com.getnet.consumerformalizada.model.oracle")
          .build();
    }

    @Bean
    @Primary
    public PlatformTransactionManager oracleTransactionManager(
      @Qualifier("oracleEntityManagerFactory") 
      LocalContainerEntityManagerFactoryBean oracleEntityManagerFactory) {
        return new JpaTransactionManager(
                Objects.requireNonNull(oracleEntityManagerFactory.getObject()));
    }

}

This is my @Transaction method:


    @Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class)
    public void iniciarInclusao(OpeInclusaoInput message) throws Exception {
        
        String idOpeRgsr = message.getIdOpeRgsr();
        int qtdUrs = message.getOperacao().getUrs().size();
        
        OperacaoSantanderEntityBuilder builder = null;  
        //Validar se a mensagem já existe na base azure
        PnrOpeSantanderEntity cttoAplicado = fmzInputService.findContratoAplicado(idOpeRgsr);
        //Se não existir nenhum registro ou não estiver com a flag de aplicado, seguir com a inclusão
        if (cttoAplicado == null || cttoAplicado.contratoNaoAplicado()) {
    
            log.info("Iniciando inclusão do contrato {} com {} UR(S).", idOpeRgsr, qtdUrs);
    
            //Salvar informações na base da azure
            //Aplica os logs iniciais na base Azure
            builder = new OperacaoSantanderEntityBuilder(message);
            Long idOpe = fmzInputService.aplicarContrato(builder.build());
    
            if (idOpe == null || idOpe.equals(Long.valueOf(0)))
                throw new Exception("Erro ao realizar inclusão do contrato via Input Service. IdOpe: " + idOpe);
    
            aplicarContratoPnr(message, null);
    
            builder.updateSucessStatus();
    
            log.info("Contrato {} incluído com sucesso.", idOpeRgsr);
        }
        //Se já existir registro e estiver aplicado, aborta
        else {
            //Não faz nada
            log.info("Contrato {} já aplicado. Status {}, será ignorado.", idOpeRgsr, cttoAplicado.getStatus());
    
            builder = new OperacaoSantanderEntityBuilder(message, cttoAplicado);
            builder.updateIgnoredStatus();
        }
        //Atualiza os dados na base azure
        this.fmzInputService.aplicarContrato(builder.build());    
    }


I tried to search on the web, but don't find a compatible solution.

0 Answers0