Question

I have configured an application to work with MyBatis-Spring and I would like to connect to multiple databases.

For this purpose, in my applicationContext.xml I have defined one datasource, one Transaction Manager (org.springframework.jdbc.datasource.DataSourceTransactionManager), one Sql Session Factory (org.mybatis.spring.SqlSessionFactoryBean) and one MapperScannerConfigurer (org.mybatis.spring.mapper.MapperScannerConfigurer) for each one of them.

Then, inside my service class I would like to perform CRUD operations with multiple databases inside the same method. As I must point to the correct transaction manager I have done what is commented below:

@Service("myServiceDB")
public class MyServiceDB implements MyService {
[...]

@Transactional(value = "TransactionManager1", rollbackFor = MyCustomException.class)

public MyUser multipleMethod(final int idUser) throws MyCustomException {

        MyUser myUser = null;
        int rowsAffected1 = -1;
        int rowsAffected2 = -1;

        try {
            myUser = this.mapperOne.getById(idUser);
            if (myObject != null) {
                rowsAffected1 = this.mapperOne.deleteByIdUser(idUser);
            }
            if (rowsAffected1 == 1) {                
                insertUser(myUser);
            }
        } catch (DataAccessException dae) {
            throw new MyCustomException(TRANSACTION_ERROR, dae);
        }

        if ((myUser == null) || (rowsAffected1 != 1)) {
            throw new MyCustomException(TRANSACTION_ERROR);
        }

        return myUser;
    }

 @Transactional(value = "TransactionManager2", rollbackFor = MyCustomException.class)

    public void insertUser(final MyUser myUser) throws MyCustomException{

        int rowsAffected = -1;
        try {
            rowsAffected = this.mapperTwo.insert(myUser);
            **throw new MyCustomException();**
        } catch (DataAccessException dae) {
            throw new MyCustomException(TRANSACTION_ERROR, dae);
        }

        //if (rowsAffected != 1) {
        //    throw new MyCustomException(TRANSACTION_ERROR);
        //}
    }

[...]
}

So each method points to its corresponding transaction manager.

If I throw the custom exception in the second method after the insert, I get the delete made in the first method correctly rolled back. However, the insert performed by the second Transaction Manager is not rolled back properly as I would desire. (i.e. the user is inserted in the second database but not deleted in the first one).

My questions are:

  • Is it possible to achieve what I want?
  • How should I configure the @Transactional annotation?

Thanks in advance.

Était-ce utile?

La solution

I found the solution here by @RisingDragon:

"If you are calling it from another local method then it will not work, because spring has no way of know that it is called and to start the transaction.

If you are calling it from a method of another class by using autowired object of the class which contains insertNotes() method, then it should work."

In my case, I created a second class (e.g. RisingDragom´s NoteClass) with some @Transactional methods (e.g. insertUser in my code) and then, the rollback worked!! This second class appeared in the debugger with the tail "$$EnhancedByCGLib".

However, if you need a method with several steps in different databases another "custom" rollback should be applied...The rollback is just applied method by method, not for the full process, so surely some data should be restored "by hand" in case of failure in any of the steps.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top