1. Overview
In this tutorial, we will learn about the concept of transactions in Spring.
We will discuss the two types of transactions programmatic and declarative transactions.
2. The code used in the tutorial
public boolean sendMoney(){
Account steve = this.accountRepository.findById(1L).get();
Account alex = this.accountRepository.findById(2L).get();
// steve is sending 100$ to alex
steve.setBalance( steve.getBalance() - 100 );
this.accountRepository.save(steve);
// Oops something went wrong while sending money to alex
if (true)
throw new RuntimeException("something went wrong");
alex.setBalance(alex.getBalance() + 100 );
this.accountRepository.save(alex);
return true;
}
3. Programmatic transaction
The programmatic transaction is achieved by implementing transaction management code in your service methods to control commit and rollback.
The transaction is committed if the code does NOT throw a runtime exception, otherwise it rolls back.
To implement programmatic transactions we need to:
1 - Inject PlatformTransactionManager in your service
2 - Create TransactionTemplate instance
3 - Call TransactionTemplate execute method
The following is an example of a programmatic transaction.
// In this example we used programatic transaction to solve the problem
// 1) Inject PlatformTransactionManager
@Autowired
PlatformTransactionManager platformTransactionManager;
public boolean sendMoney(){
// 2) Create TransactionTemplate instance
TransactionTemplate transactionTemplate = new TransactionTemplate();
// 3) Call TransactionTemplate execute method
transactionTemplate.execute(new TransactionCallback <Object>() {
@Override
public Object doInTransaction(TransactionStatus transactionStatus) {
Account steve = accountRepository.findById(1L).get();
Account alex = accountRepository.findById(2L).get();
steve.setBalance( steve.getBalance() - 100 );
accountRepository.save(steve);
// RuntimeException => Rollback previous query(ies)
if (true)
throw new RuntimeException("something went wrong");
alex.setBalance(alex.getBalance() + 100 );
accountRepository.save(alex);
return true;
}
});
return true;
}
Because we have a runtime exception the money is not debited from Steve's account.
Important: Transaction is rolled-back only if we get an unchecked exception ( Runtime exception or DataAccessException ) or if you call setRollBackOnly method from TransactionStatus.
3. Declarative transaction management
Declarative transaction is straightforward; to use a declarative transaction you simply need to add to your transactional methods @Transactional annotation.
@Transactional
public boolean sendMoney(){
Account steve = this.accountRepository.findById(1L).get();
Account alex = this.accountRepository.findById(2L).get();
steve.setBalance( steve.getBalance() - 100 );
this.accountRepository.save(steve);
// ** Rolls-back because we have @Transactional annotation **
if (true)
throw new RuntimeException("something went wrong");
alex.setBalance(alex.getBalance() + 100 );
this.accountRepository.save(alex);
return true;
}
You can also appy the @Transactional annotation in the class level, this way all public methods in the class will be defined as transactional.

0 Comments