上一次桶至,和朋友們聊了聊事務(wù)失效場景拿诸,我已經(jīng)整理成了文章,Java開發(fā)中塞茅,導致事務(wù)失效的場景。緊接著有提到了大事務(wù)問題季率,經(jīng)過一番激烈的討論野瘦,對這個問題也算是有了一些輸出場景。下面我簡要描述一下。
一鞭光、概念
什么是大事務(wù)吏廉?簡要來說就是:運行時間比較長,操作的數(shù)據(jù)比較多的事務(wù)惰许。
二席覆、大事務(wù)引發(fā)的問題
大事務(wù)對系統(tǒng)來說,是導致響應(yīng)緩慢的一個重要原因汹买。它會引發(fā)一些列問題佩伤,諸如:鎖等待、死鎖晦毙、接口超時生巡、數(shù)據(jù)庫主從延遲、事務(wù)回滾時間長见妒、數(shù)據(jù)庫連接池被占滿等問題孤荣。
三、形成原因或解決辦法
1. 將查詢放到事務(wù)外處理须揣。
@Transactional(rollbackFor=Exception.class)
public void save(Entity entity) {
selectData();
addData(entity );
updateData(entity );
}
如上代碼所示盐股,一個事務(wù)中,同事包含了查詢耻卡,新增疯汁,修改,這種時候劲赠,就容易出現(xiàn)大事務(wù)涛目。當然,改造也很簡單凛澎,把查詢的放到事務(wù)外霹肝。這里就要引入另一種事務(wù)實現(xiàn)方式:編程式事務(wù)。上述代碼是:聲明式事務(wù)塑煎。
@Autowired
privateTransactionTemplate transactionTemplate;
public void save(Entity entity) {
selectData();
transactionTemplate.execute((obj) => {
addData(entity );
updateData(entity );
returnBoolean.TRUE;
})
}
2.盡量少用聲明式事務(wù)@Transactional
我相信這種事務(wù)使用場景應(yīng)該是非常廣泛的沫换,包括我所參與的項目中,使用這樣的方式來配置事務(wù)占有率也是非常高的最铁,但是為什么會建議少使用這種方式呢讯赏?
2.1 我們都知道,spring事務(wù)其實就是通過aop切面來起作用的冷尉,如果使用不當漱挎,會使得事務(wù)失效,詳見我的上一篇文章雀哨。
2.2 這種事務(wù)聲明磕谅,一般是用于業(yè)務(wù)代碼中的某個方法私爷,這種方法內(nèi),往往可能存在多種數(shù)據(jù)庫操作膊夹,這種時候衬浑,就容易產(chǎn)生大事務(wù),如上述例子放刨。解決方法依然是:使用編程式事務(wù)來管控工秩。
3.事務(wù)中,存在RPC調(diào)用
在事務(wù)中进统,如果使用了外部的遠程調(diào)用助币、內(nèi)部業(yè)務(wù)調(diào)用、MQ或Redis等麻昼,因為調(diào)用過程中的不可控的網(wǎng)絡(luò)延遲因素奠支,導致大事務(wù)發(fā)生或產(chǎn)生異常導致事務(wù)回滾。
@Transactional(rollbackFor=Exception.class)
public void save(Entity entity) {
feignClient.read();
redisTemplate.get();
addData();
}
解決辦法依然是抚芦,把需要添加事務(wù)的部分倍谜,添加事務(wù),最常用的依然是編程式事務(wù)叉抡。
@Autowired
privateTransactionTemplate transactionTemplate;
public void save(Entity entity) {
feignClient.read();
redisTemplate.get();
transactionTemplate.execute((obj) => {
addData();
updateData();
returnBoolean.TRUE;
})
}
4.異步處理
如果在業(yè)務(wù)邏輯中尔崔,需要做多步驟、多階段操作或消息發(fā)送等褥民,我們可以采取異步操作來處理這部分事情季春。把事務(wù)盡量做到精確化。
@Autowired
privateTransactionTemplate transactionTemplate;
public void save(Entity entity) {
transactionTemplate.execute((obj) => {
addData(entity);
returnBoolean.TRUE;
})
sendMessage();
}