Spring的交易管理(中國叫做事務管理)(Transactoinal Management)中,當由同類別中一個無交易管理(無@Transactional
)的方法呼叫另一個有交易管理(有@Transactional
)的方法時,有交易管理的方法發生例外時資料不會回滾(rollback)。
例如下面的DemoService
類別的modifyName()
為無交易管理方法,addModifyLog()
為有交易管理方法。
在modifyName()
中呼叫了addModifyLog()
,當addModifyLog()
執行發生例外錯誤時不會回滾。
DemoService
package com.abc.demo.service;
import com.abc.demo.entity.ModifyLog;
import com.abc.demo.repository.EmployeeRepository;
import com.abc.demo.repository.ModifyLogRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.Date;
@Service
public class DemoService {
@Autowired
private EmployeeRepository employeeRepository;
@Autowired
private ModifyLogRepository modifyLogRepository;
/**
* 無交易管理的方法
*/
public void modifyName(long id, String name) {
employeeRepository.findById(id).map(e -> {
e.setName(name);
return employeeRepository.save(e);
}).ifPresent(e -> addModifyLog( // 呼叫同類別中有交易管理的方法
e.getClass().getSimpleName().toUpperCase(),
e.getId()));
}
/**
* 有交易管理的方法
*/
@Transactional
public void addModifyLog(String tableName, long tableId) {
ModifyLog log = ModifyLog.builder()
.tableName(tableName)
.tableId(tableId)
.modifyDate(new Date())
.build();
modifyLogRepository.save(log);
throw new RuntimeException("Database error.");
}
}
因為Spring的@Transactional
是基於Spring AOP的proxy代理來實現,由客戶端調用的方法為proxy的方法,而被調用的同物件方法則是原物件的方法而非proxy的方法,所以被調用的同物件方法的@Transactional
會沒有效果。這也是private
方法加上@Transactional
也無交易管理的效果的原因。
參考官方文件說明
In proxy mode (which is the default), only external method calls coming in through the proxy are intercepted. This means that self-invocation (in effect, a method within the target object calling another method of the target object) does not lead to an actual transaction at runtime even if the invoked method is marked with @Transactional. Also, the proxy must be fully initialized to provide the expected behavior, so you should not rely on this feature in your initialization code (that is, @PostConstruct).
參考github。
沒有留言:
張貼留言