1. 程式人生 > >記一次 Spring 事務配置踩坑記

記一次 Spring 事務配置踩坑記

pub lock loaded 查詢條件 setprop ins 能夠 get 數據

記一次 Spring 事務配置踩坑記

問題描述:(SpringBoot + MyBatisPlus)

業務邏輯偽代碼如下。理論上,插入數據 t1 後,xxService.getXxx() 方法的查詢條件會不滿足,會查詢不到數據。結果事與願違,後一次的查詢,居然查到了數據。

void saveXxx(){
xxService.getXxx(); // 查到一條數據 data1
xxService.insert(); // 插入一條數據 t1
xxService.getXxx(); // 查到一條數據 data1
}

分析過程:

拋棄業務邏輯,在一個新的 service 中寫了一個最簡單的測試,查詢 --> 插入 --> 查詢。為了保證兩者具有可比性,sql 都從原 Mapper 中拷貝過去。但是依然重現不了問題。神奇的是出現了如下的情況:

@Transactional
void testMyBatis(){
yyService.getYyy(); // 查到一條數據 data1
yyService.insert(); // 插入一條數據 t1
yyService.getYyy(); // 查不到數據
xxService.getXxx(); // 查到一條數據 data1
}

理論上,yyService.getYyy() 與 xxService.getXxx() 應該都查不到數據才對,結果只有 xxService.getXxx() 能查到。

開始懷疑事務的問題,是不是 xxService.getXxx() 新開啟了一個事務去查詢,只有這樣,xxService.getXxx() 的查詢條件才不受當前事務插入的數據所影響。

檢查項目中的事務配置,除了配置了註解式事務外,還有如下的聲明式事務配置:

@Bean
public TransactionInterceptor txAdvice() {
NameMatchTransactionAttributeSource source = new NameMatchTransactionAttributeSource();
RuleBasedTransactionAttribute readOnlyTx = new RuleBasedTransactionAttribute();
readOnlyTx.setReadOnly(true);
readOnlyTx.
setPropagationBehavior(TransactionDefinition.PROPAGATION_NOT_SUPPORTED );
RuleBasedTransactionAttribute requiredTx = new RuleBasedTransactionAttribute();
requiredTx.setRollbackRules(Collections.singletonList(new RollbackRuleAttribute(Exception.class)));
requiredTx.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
requiredTx.setTimeout(TX_METHOD_TIMEOUT);
Map<String, TransactionAttribute> txMap = new HashMap<>();
txMap.put("add*", requiredTx);
txMap.put("save*", requiredTx);
txMap.put("insert*", requiredTx);
txMap.put("update*", requiredTx);
txMap.put("delete*", requiredTx);
txMap.put("get*", readOnlyTx);
txMap.put("query*", readOnlyTx);
source.setNameMap( txMap );
TransactionInterceptor txAdvice = new TransactionInterceptor(transactionManager, source);
return txAdvice;
}

就是這一行配置搞的鬼:readOnlyTx.setPropagationBehavior(TransactionDefinition.PROPAGATION_NOT_SUPPORTED ); get*開頭的方法都加了只讀事務,而只讀事務是以非事務方式運行,如果當前存在事務,則把當前事務掛起。

這樣就解釋了為什麽 xxService.getXxx() 方法能夠查到數據了,它是在當前事務之外查詢的數據。

附:還是使用註解式事務吧 ^_^

記一次 Spring 事務配置踩坑記