本篇介紹Spring TransactionTemplate
如何在程式中手動回滾交易。
範例環境:
- Spring Boot 2.3.2
Spring進行資料庫交易時,除了在交易的方法前加上@Transactional
來管理交易外,Spring的TransactionTemplate
提供在程式中"手動"管理交易的方法。
下面DepartmentService
的deleteDepartment(Long id)
依傳入的部門ID來刪除部門資料及所屬員工資料,資料異動操作共兩次。這邊用TransactionTemplate
以程式的方式手動管理交易。
建構TransactionTemplate
物件需傳入PlatformTransactionManager
,此為實際負責commit及rollback的介面。Spring預設已註冊PlatformTransactionManager
的bean,因此以建構式注入DepartmentService()
並建立TransactionTemplate
物件。
DepartmentService
package com.abc.demo.service;
import com.abc.demo.entity.Employee;
import com.abc.demo.repository.DepartmentRepository;
import com.abc.demo.repository.EmployeeRepository;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
import org.springframework.transaction.support.TransactionTemplate;
import java.sql.SQLException;
import java.util.List;
@Log4j2
@Service
public class DepartmentService {
@Autowired
private DepartmentRepository departmentRepository;
@Autowired
private EmployeeRepository employeeRepository;
private final TransactionTemplate transactionTemplate;
public DepartmentService(PlatformTransactionManager platformTransactionManager) {
transactionTemplate = new TransactionTemplate(platformTransactionManager);
}
// @Transactional
public void deleteDepartment(Long id) {
List<Employee> employeeList = employeeRepository.findByDepartmentId(id);
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus transactionStatus) {
try {
employeeRepository.deleteInBatch(employeeList); // 刪除部門所屬員工資料
departmentRepository.deleteById(id); // 刪除部門資料
if (id == 1L) {
throw new SQLException("Database transaction error!!"); // 模擬交易發生錯誤
}
} catch (SQLException e) {
log.error(e.getMessage());
transactionStatus.setRollbackOnly(); // rollback
}
}
});
}
}
TransactionTemplate.execute(TransactionCallback<T> action)
方法用來執行資料庫操作,傳入一個TransactionCallback
實例作為參數,並在TransactionCallback
的實作中執行資料庫操作程式並捕捉錯誤。若操作不回傳值則改用TransactionCallbackWithoutResult
。
當錯誤發生時呼叫TransactionStatus.setRollbackOnly()
進行rollback,因此前面刪除員工及部門資料的動作會回復到交易前的狀態。
參考github
沒有留言:
張貼留言