Vinod S P
Vinod S P

Reputation: 23

How to achieve transaction rollback in spring boot if any exception occurs inside any method

In spring boot I am trying to rollback transactions if any exception occurs anywhere inside the rest api method but it was doing transaction rollback only for that particular method not for all methods, And also help me in preventing response even after exception thrown. Please ignore my question asking style and format.

Here is the rest api controller class:

@RequestMapping(path = "/formDetails", produces = MediaType.APPLICATION_JSON_VALUE, method = RequestMethod.POST)
    public ManadateFormResponse generateMandateForm(@RequestBody ManadateFormRequest manadateFormRequest,
            WebRequest request) throws Exception {
        
        ManadateFormResponse manadateFormResponse = new ManadateFormResponse();

        String errorStatus = environment.getRequiredProperty("rbi.status.error").trim();
        String adminZone = environment.getRequiredProperty("rbi.admin.zone").trim();
        String neft = environment.getRequiredProperty("payment.channel.type.neft").trim();
        String rtgs = environment.getRequiredProperty("payment.channel.type.rtgs").trim();
        String entityType = environment.getRequiredProperty("entity.type." + manadateFormRequest.getDutyType());

        try {
            
            Long[] l_tokens = nEFTRTGSService.validateChallans(manadateFormRequest.getSelectedChallans());

            final List<Long> tokens = Arrays.asList(l_tokens);
            List<EpaymentMainEntity> challans = nEFTRTGSService.loadChallans(Arrays.asList(l_tokens),
                    request.getLocale());

            List<Map<String, Object>> challanDetails = CommonFunctions.processMajorHeads(challans, adminZone);

            final Map<String, Object> basicData = CommonFunctions.getTotalDutyAndUserAndExpiryDate(challans);

            String referenceNumber = EpayRefID.generateReferenceNumber(entityType, manadateFormRequest.getDocType());
            if (referenceNumber.length() > 20) {
                throw new ReferenceNumberGenerationException(messages
                        .getMessage("message.exception.referenceNumberGenerationException", null, request.getLocale()));
            }

            nEFTRTGSService.initiatePayment(tokens, referenceNumber, challans, manadateFormRequest.getPaymentChannel(),
                    request.getLocale());

            
            new Thread(() -> {
                try {
                    
                    basicData.put("refernceNumber", referenceNumber);
                    basicData.put("challanDetails", challanDetails);
                    Map<String, Object> response = nEFTRTGSService.processNEFTRTGS(basicData);
                    String status_cd = ((String) response.get("Status_cd")).trim();
                    if (response == null || (status_cd).equals(errorStatus)) {
                        response = nEFTRTGSService.processNEFTRTGS(basicData);
                        
                        status_cd = ((String) response.get("Status_cd")).trim();
                        if (response == null || (status_cd).equals(errorStatus)) {
                            response = nEFTRTGSService.processNEFTRTGS(basicData);
                            
                        }
                    }
                    
                    List<EpaymentMainEntity> t_challans = nEFTRTGSService.loadChallans(Arrays.asList(l_tokens),
                            request.getLocale());


                    nEFTRTGSService.updateResponse(response, referenceNumber, t_challans);
                } catch (Exception e) {
                    throw new APIServiceException(e.getLocalizedMessage());

                }
            }).start();

            epay3Service.postPaymentDetails(new IGEpay3DTO(referenceNumber), request.getLocale());

            try {
                Object ExpDate = basicData.get("expiryDate");

                String strExpDate = String.valueOf(ExpDate);
                Date ExpDt = DateTimeUtility.parseJavaTimestamp(strExpDate);

                String dutyAmt = basicData.get("totalDuty").toString();
                BigDecimal totalDuty = new BigDecimal(dutyAmt);

                manadateFormResponse = nEFTRTGSService.generateMandateForm(referenceNumber, ExpDt, totalDuty,
                        request.getLocale());

            } catch (ManadateFormGenerationException exception) {
                throw exception;
            }
        } catch (Exception e) {
            throw new ManadateFormGenerationException(messages.getMessage("message.exception.manadateFormGenerationException", null, request.getLocale()));

        }

        return manadateFormResponse;

    }

All the methods in implementations had @Transactional in service class and I tried adding @Transactional for rest api still not worked. Consider initiatePayment executed without any exceptions and some exception occurs in processNEFTRTGS method, it was only doing rollback for processNEFTRTGS method not for initiatePayment and also it was giving response return manadateFormResponse. So how can I achieve transaction rollback if any exception occurs in anywhere and need to prevent giving response if any exception occurs, Example initiatePayment, processNEFTRTGS ,updateResponse executed without any errors and exception occurred in postPaymentDetails at that time should rollback above transactions and also it should not give manadateFormResponse.

Upvotes: 2

Views: 1723

Answers (1)

Ramin Safar Manesh
Ramin Safar Manesh

Reputation: 257

First you have to configure the Transaction Manger if you havnt't yet: Transactions with Spring and JPA

@Configuration
@EnableTransactionManagement
public class PersistenceJPAConfig{

   @Bean
   public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
       //...
   }

   @Bean
   public PlatformTransactionManager transactionManager() {
      JpaTransactionManager transactionManager = new JpaTransactionManager();
      transactionManager.setEntityManagerFactory(entityManagerFactory().getObject());
      return transactionManager;
   }
}

And the you put the transactional annotation on top of your target method:

@Transactional
public void saveTransaction(){
 saveSomethingIntoDb();
 throw new RuntimeException("Error");
}

Now the transaction manger will rollback the DB-Changes from the command saveSomethingIntoDb

Upvotes: 0

Related Questions