Spring @Transactional 事務回滾機制
阿新 • • 發佈:2018-12-10
Srping 事務
在Spring 的世界裡面我們一般使用@Transactional
註解在對應方法上面宣告為一個事務方法。
但是在預設不寫@Transactional(rollbackFor = Exception.class)
預設回滾RuntimeException
今天就希望通過原始碼的方式瞭解一下@Transactional
的回滾機制。
Spring 原始碼解析
首先我們先編寫一個測試demo如下所示
@Service
public class TestService {
@Autowired
private ModelRepo modelRepo;
@Transactional(rollbackFor = {Exception.class,ClassNotFoundException.class,IOException.class} ,
noRollbackFor = FileNotFoundException.class)
public void test() throws Throwable{
Model model = new Model();
modelRepo.save(model);
throw new FileNotFoundException ();
}
}
接著我們開始進入Debug
當我們的程式碼丟擲異常時Spring容器會建立一個RuleBasedTransactionAttribute
物件,該物件就是我們那個方法上面@Transactional
的一個描述。
//基於規則的事務屬性
public class RuleBasedTransactionAttribute
extends DefaultTransactionAttribute implements Serializable {
//這就是那些 rollbackFor noRollbackFor 異常的處理器
@Nullable
private List<RollbackRuleAttribute> rollbackRules;
...
}
//這個就是異常回滾處理器的類
//回滾規則屬性
public class RollbackRuleAttribute implements Serializable{
/**
* The {@link RollbackRuleAttribute rollback rule} for
* {@link RuntimeException RuntimeExceptions}.
*/
//這裡預設就有個RuntimeException處理
//但是 @Transactional 預設回滾和它貌似沒有什麼關係
public static final RollbackRuleAttribute ROLLBACK_ON_RUNTIME_EXCEPTIONS =
new RollbackRuleAttribute(RuntimeException.class);
private final String exceptionName;
//這裡就將待處理類名稱儲存起來
public RollbackRuleAttribute(Class<?> clazz) {
Assert.notNull(clazz, "'clazz' cannot be null");
if (!Throwable.class.isAssignableFrom(clazz)) {
throw new IllegalArgumentException(
"Cannot construct rollback rule from [" + clazz.getName() + "]: it's not a Throwable");
}
this.exceptionName = clazz.getName();
}
//這兩個方法是很關鍵的是Spring核心處理邏輯 後續會繼續貼上程式碼
public int getDepth(Throwable ex) {
return getDepth(ex.getClass(), 0);
}
private int getDepth(Class<?> exceptionClass, int depth) {
//異常物件能夠被代理嗎? xxx.xxx.xxx.$xx 防止別人騷操作?
if (exceptionClass.getName().contains(this.exceptionName)) {
// Found it!
return depth;
}
// If we've gone as far as we can go and haven't found it...
//找不到而且已經找到頭了
if (exceptionClass == Throwable.class) {
return -1;
}
//兒子找不到,就找他爹咯
return getDepth(exceptionClass.getSuperclass(), depth + 1);
}
... //略
}
在初始化一個異常回滾判定的 基於規則的事務屬性 RuleBasedTransactionAttribute
物件之後就進入了TransactionAspectSupport
(交易方面支援)的程式碼
public abstract class TransactionAspectSupport
implements BeanFactoryAware, InitializingBean {
...
protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass,
final InvocationCallback invocation) throws Throwable {
// If the transaction attribute is null, the method is non-transactional.
TransactionAttributeSource tas = getTransactionAttributeSource();
final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);
final PlatformTransactionManager tm = determineTransactionManager(txAttr);
final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);
//這還要是有 回撥首選平臺事務管理器 的才可以進入
//不夠我們一般都是進入這個程式碼塊邏輯進行處理的
if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) {
// Standard transaction demarcation with getTransaction and commit/rollback calls.
TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);
Object retVal = null;
try {
//核心程式碼
// This is an around advice: Invoke the next interceptor in the chain.
// This will normally result in a target object being invoked.
//執行Service的相關方法
retVal = invocation.proceedWithInvocation();
}
catch (Throwable ex) {
// target invocation exception
//處理Exception判定回滾規則
completeTransactionAfterThrowing(txInfo, ex);
throw ex;
}
finally {
cleanupTransactionInfo(txInfo);
}
commitTransactionAfterReturning(txInfo);
return retVal;
}
else {
... //程式碼太多久不貼了
}
}
...
//進入 completeTransactionAfterThrowing 方法看看
protected void completeTransactionAfterThrowing(@Nullable TransactionInfo txInfo, Throwable ex) {
if (txInfo != null && txInfo.getTransactionStatus() != null) {
if (logger.isTraceEnabled()) {
logger.trace("Completing transaction for [" + txInfo.getJoinpointIdentification() +
"] after exception: " + ex);
}
//核心關鍵的處理邏輯來了 txInfo.transactionAttribute.rollbackOn(ex)
if (txInfo.transactionAttribute != null && txInfo.transactionAttribute.rollbackOn(ex)) {
try {
txInfo.getTransactionManager().rollback(txInfo.getTransactionStatus());
}
catch (TransactionSystemException ex2) {
logger.error("Application exception overridden by rollback exception", ex);
ex2.initApplicationException(ex);
throw ex2;
}
catch (RuntimeException | Error ex2) {
logger.error("Application exception overridden by rollback exception", ex);
throw ex2;
}
}
else {
// 發話了我們不會回滾這個異常
// We don't roll back on this exception.
// Will still roll back if TransactionStatus.isRollbackOnly() is true.
try {
txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());
}
catch (TransactionSystemException ex2) {
logger.error("Application exception overridden by commit exception", ex);
ex2.initApplicationException(ex);
throw ex2;
}
catch (RuntimeException | Error ex2) {
logger.error("Application exception overridden by commit exception", ex);
throw ex2;
}
}
}
}
}
搞事搞事 我們進入 txInfo.transactionAttribute.rollbackOn(ex)
這個東西看看
第一層
public abstract class DelegatingTransactionAttribute
extends DelegatingTransactionDefinition
implements TransactionAttribute, Serializable {
...
@Override
public boolean rollbackOn(Throwable ex) {
return this.targetAttribute.rollbackOn(ex);
}
...
}
進入this.targetAttribute.rollbackOn(ex);
沒錯就是上面的RuleBasedTransactionAttribute
public class RuleBasedTransactionAttribute
extends DefaultTransactionAttribute implements Serializable {
...
@Override
public boolean rollbackOn(Throwable ex) {
if (logger.isTraceEnabled()) {
logger.trace("Applying rules to determine whether transaction should rollback on " + ex);
}
RollbackRuleAttribute winner = null;
int deepest = Integer.MAX_VALUE;
//因為這裡的處理器集合總是回滾的在前面,不回滾的在後面所以你認為不回滾一定無敵,那麼你就錯咯
if (this.rollbackRules != null) {
for (RollbackRuleAttribute rule : this.rollbackRules) {
int depth = rule.getDepth(ex);
//騷還是Spring的人騷 這裡他麼是個就近原則
// 所以理論上 rollbackFor noRollbackFor 同一個類那麼應該是回滾的 可以試試
//就近原則,一樣近走回滾
if (depth >= 0 && depth < deepest) {
deepest = depth;
winner = rule;
}
}
}
if (logger.isTraceEnabled()) {
logger.trace("Winning rollback rule is: " + winner);
}
// User superclass behavior (rollback on unchecked) if no rule matches.
if (winner == null) {
logger.trace("No relevant rollback rule found: applying default rules");
return super.rollbackOn(ex);
}
return !(winner instanceof NoRollbackRuleAttribute);
}
...
}
rule.getDepth(ex);
public int getDepth(Throwable ex) {
//重0開始計數
return getDepth(ex.getClass(), 0);
}
//就是上面的rule.getDepth(ex); 獲取深度,結合上下文 就近原則了
private int getDepth(Class<?> exceptionClass, int depth) {
if (exceptionClass.getName().contains(this.exceptionName)) {
// Found it!
return depth;
}
// If we've gone as far as we can go and haven't found it...
if (exceptionClass == Throwable.class) {
return -1;
}
return getDepth(exceptionClass.getSuperclass(), depth + 1);
}
有張圖片配合一下,可以看出裡面的處理器總是前面的是允許回滾的,後面的是不進行回滾的。
可以看出裡面的處理器總是前面的是允許回滾的,後面的是不進行回滾的。
以上就是@Transactional
有配置 noRollbackFor ,rollbackFor 的執行流程
Spring @Transactional 無配置回滾執行
public class RuleBasedTransactionAttribute
extends DefaultTransactionAttribute
implements Serializable {
...
@Override
public boolean rollbackOn(Throwable ex) {
if (logger.isTraceEnabled()) {
logger.trace("Applying rules to determine whether transaction should rollback on " + ex);
}
RollbackRuleAttribute winner = null;
int deepest = Integer.MAX_VALUE;
if (this.rollbackRules != null) {
for (RollbackRuleAttribute rule : this.rollbackRules) {
int depth = rule.getDepth(ex);
if (depth >= 0 && depth < deepest) {
deepest = depth;
winner = rule;
}
}
}
if (logger.isTraceEnabled()) {
logger.trace("Winning rollback rule is: " + winner);
}
// User superclass behavior (rollback on unchecked) if no rule matches.
//無配置時 進入了這裡了 找爹看看怎麼操作
if (winner == null) {
logger.trace("No relevant rollback rule found: applying default rules");
return super.rollbackOn(ex);
}
return !(winner instanceof NoRollbackRuleAttribute);
}
...
}
看看爹怎麼操作的
public class DefaultTransactionAttribute
extends DefaultTransactionDefinition
implements TransactionAttribute {
...
// 就這麼直白 裁判殺死了比賽 RuntimeException Error 回滾,其他再見
@Override
public boolean rollbackOn(Throwable ex) {
return (ex instanceof RuntimeException || ex instanceof Error);
}
...
}