失效場(chǎng)景
使用限制
1. 可繼承(CGLIB代理)
反例:被final、static修飾
CGLIB是通過(guò)生成目標(biāo)類(lèi)子類(lèi)的方式生成代理類(lèi)的弱卡,被final喻旷、static修飾后,無(wú)法繼承父類(lèi)與父類(lèi)的方法躏啰。
2. 被public修飾
不支持非public修飾的方法進(jìn)行事務(wù)管理
3. 需要被Spring管理
都沒(méi)有被Spring管理成為IOC容器中的一個(gè)bean趁矾,更別說(shuō)被事務(wù)切面代理到了。
4. 需要通過(guò)bean調(diào)用
事務(wù)的管理是通過(guò)代理執(zhí)行的方式生效的给僵,如果是方法內(nèi)部調(diào)用毫捣,將不會(huì)走代理邏輯,也就調(diào)用不到了。
5. 不支持多線程調(diào)用
事務(wù)信息是跟線程綁定的培漏。
6. 數(shù)據(jù)庫(kù)本身要支持事務(wù)
比如Mysql的Myisam存儲(chǔ)引擎是不支持事務(wù)的溪厘,只有innodb存儲(chǔ)引擎才支持。
7. 需要開(kāi)啟事務(wù)
在Springboot項(xiàng)目中已經(jīng)不存在了牌柄,已經(jīng)有DataSourceTransactionManagerAutoConfiguration默認(rèn)開(kāi)啟了事務(wù)管理畸悬。
代碼實(shí)例
@Slf4j
@Service
public class TestServiceImpl implements TestService {
@Resource
private TestMapper testMapper;
@Resource
private TestServiceImpl testService;
@Override
public void test() throws Exception {
testService.test2();
}
/**
* @description 本類(lèi)方法調(diào)用本類(lèi)事務(wù)方法會(huì)導(dǎo)致事務(wù)不生效
* 事務(wù)實(shí)現(xiàn)需要通過(guò)代理所以
* 調(diào)用的方法必須為public
* 且通過(guò)bean 調(diào)用
* @date 2024/11/26 18:22
**/
public void test0() throws Exception {
// 不可以回滾
// 本類(lèi)方法調(diào)用本類(lèi)事務(wù)方法會(huì)導(dǎo)致事務(wù)不生效
test1();
// 可以回滾
testService.test2();
}
/**
* @description 事物不支持多線程,需要用同步方法包裹
* @date 2024/11/27 10:00
**/
public synchronized void testMultiThreading() throws Exception {
testService.test1();
}
/**
* @description 這樣是不行的珊佣,可能跳出同步方法但事務(wù)未提交蹋宦,就有另一個(gè)線程來(lái)執(zhí)行了
* @date 2024/11/27 10:03
**/
@Transactional
public synchronized void testMultiThreadingError() throws Exception {
test1();
}
/**
* @description 未指定異常,只會(huì)回滾Error咒锻,RuntimeException以及它們的子類(lèi)
* @date 2024/11/26 17:57
**/
@Transactional
public void test1() throws Exception {
TestDO testDO = TestDO.builder().name("name").code("code").build();
testMapper.insert(testDO);
// 可以回滾
throw new Error();
// throw new RuntimeException();
// 不可以回滾
// throw new Exception();
}
/**
* @description 指定異忱淙撸回滾, 會(huì)回滾Error惑艇,Exception以及它們的子類(lèi)(Error不需要指定)
* @date 2024/11/26 17:58
**/
@Transactional(rollbackFor = Exception.class)
public void test2() throws Exception {
TestDO testDO = TestDO.builder().name("name").code("code").build();
testMapper.insert(testDO);
// 都可以回滾
// throw new RuntimeException();
throw new Error();
// throw new Exception();
}
}
結(jié)論
結(jié)論一:對(duì)于@Transactional可以保證RuntimeException蒿辙,Error的回滾,如果想保證非RuntimeException錯(cuò)誤的回滾滨巴,需要加上rollbackFor = Exception.class 參數(shù)思灌。
結(jié)論二:try catch只是對(duì)異常是否可以被@Transactional 感知 到有影響。如果錯(cuò)誤拋到切面可以感知到的地步恭取,那就可以起作用泰偿。
結(jié)論三:由于REQUIRED屬性,“兩個(gè)事務(wù)”其實(shí)是一個(gè)事務(wù)蜈垮,處理能力看報(bào)錯(cuò)時(shí)刻耗跛,是否添加了處理非RuntimeException的能力。