0

I have two transaction manager for two database. I need to persist same data into both databases. If one transaction failed, other one need rollback. I have done like below

public interface DataService {
    void saveData();
}

@Service
public class DataServiceImpl implements DataService {

    @Autowired
    private DataRepository dataRepository;
    
    @Autowired
    private OrDataRepository orDataRepository;
    
    @Autowired
    @Qualifier("orService")
    private OrService orDataServiceImpl;
    
    
    @Override
    @Transactional(transactionManager = "transactionManager", rollbackFor = {RuntimeException.class})
    public void saveData() {
        Data data = new Data();
        data.setCompKey(UUID.randomUUID().toString().substring(1,5));
        data.setName("data");
        dataRepository.save(data);
        orDataServiceImpl.save();
        //throw new RuntimeException("");
    }
}

public interface OrService {
    void save();
}


@Service("orService")
public class OrDataServiceImpl implements OrService {
    @Autowired
    private OrDataRepository orDataRepository;
    
    
    @Override
    @Transactional(rollbackFor = {RuntimeException.class})
    public void save() {
        OrData data = new OrData();
        data.setCompKey(UUID.randomUUID().toString().substring(1,5));
        data.setName("ordata");
        orDataRepository.save(data);
    }
}

I have two transaction manager (entityManager & orEntityManager) for two different DB.

If any exception in OrDataServiceImpl save method, data is not getting persisted in both DB. But if any exception in DataServiceImpl saveData method, data is getting persisted into OrData table.

I want to rollback the data from both DB if any exception.

chainedTransactionManager is deprecated. So can't use. atomikos and bitronix also can't use due to some restrictions. Kindly suggest better way to achieve distributed transation

Sangeetharaj
  • 169
  • 3
  • 14

1 Answers1

0
  • The code need to be refactored, edit the DataServiceImpl.save() method.

    Comment the orDataServiceImpl.save() line

     public void saveData() {
     Data data = new Data();
     data.setCompKey(UUID.randomUUID().toString().substring(1,5));
     data.setName("data");
     dataRepository.save(data);
     //orDataServiceImpl.save();
     //throw new RuntimeException("");
     }
    
  • Refactor/Edit the OrDataService Interface

     public interface OrDataService {
    
     void save(String uuid); 
     void delete(String uuid); 
    //will be use for compensating transaction
    

    }

  • Update the OrDataServiceImpl class to implement above interface

  • Write new orchestration Method and use compensating transaction to rollback

    pseudo code

    1. call OrDataServiceImpl.save()
    2. if step#1 was success
    3.   -> DataServiceImpl.saveData()
      
    4.  if Exception at step#3,
      
    5.       ->OrDataServiceImpl.delete() [//to rollback]
      
    6. else if, Exception at step#1 //do nothing
kus
  • 446
  • 3
  • 7
  • Thanks for the reply. For simple insert it's easy to follow above mentioned flow. For delete, complex update we can't use it. I feel that this is not a rollback. We are programmatically deleting the data – Sangeetharaj Apr 20 '22 at 01:24
  • This is as per with Saga Orchestrator Pattern, of course you can explore - Saga Choreography pattern. And more complex 2 PC commit - which most of the time doesn't work as expected.. – kus Apr 20 '22 at 01:52
  • Agree. I went through compensating transaction, saga design pattern. For larger application we can't write a logic to undo for each transaction. If we follow saga design pattern it will need huge effort. – Sangeetharaj Apr 20 '22 at 02:03
  • I am thinking once first transaction got success i can call the second transaction method. If first transaction failed, i am not going to call second transaction method. Is there any way to rollback the first transaction if second transaction failed – Sangeetharaj Apr 20 '22 at 02:06