国产片侵犯亲女视频播放_亚洲精品二区_在线免费国产视频_欧美精品一区二区三区在线_少妇久久久_在线观看av不卡

服務(wù)器之家:專(zhuān)注于服務(wù)器技術(shù)及軟件下載分享
分類(lèi)導(dǎo)航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術(shù)|正則表達(dá)式|C/C++|IOS|C#|Swift|Android|VB|R語(yǔ)言|JavaScript|易語(yǔ)言|vb.net|

服務(wù)器之家 - 編程語(yǔ)言 - Java教程 - 完美解決Spring聲明式事務(wù)不回滾的問(wèn)題

完美解決Spring聲明式事務(wù)不回滾的問(wèn)題

2020-11-04 16:46Java教程網(wǎng) Java教程

下面小編就為大家?guī)?lái)一篇完美解決Spring聲明式事務(wù)不回滾的問(wèn)題。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧

疑問(wèn),確實(shí)像往常一樣在service上添加了注解 @Transactional,為什么查詢(xún)數(shù)據(jù)庫(kù)時(shí)還是發(fā)現(xiàn)有數(shù)據(jù)不一致的情況,想想肯定是事務(wù)沒(méi)起作用,出現(xiàn)異常的時(shí)候數(shù)據(jù)沒(méi)有回滾。于是就對(duì)相關(guān)代碼進(jìn)行了一番測(cè)試,結(jié)果發(fā)現(xiàn)一下踩進(jìn)了兩個(gè)坑,確實(shí)是事務(wù)未回滾導(dǎo)致的數(shù)據(jù)不一致。

下面總結(jié)一下經(jīng)驗(yàn)教訓(xùn):

Spring事務(wù)的管理操作方法

編程式的事務(wù)管理

實(shí)際應(yīng)用中很少使用

通過(guò)使用TransactionTemplate 手動(dòng)管理事務(wù)

聲明式的事務(wù)管理

開(kāi)發(fā)中推薦使用(代碼侵入最少)

Spring的聲明式事務(wù)是通過(guò)AOP實(shí)現(xiàn)的

主要掌握聲明式的事務(wù)管理。

spring事務(wù)不回滾的兩個(gè)原因

總結(jié)一下導(dǎo)致事務(wù)不回滾的兩個(gè)原因,一是Service類(lèi)內(nèi)部方法調(diào)用,二是try...catch異常。

1. Service類(lèi)內(nèi)部方法調(diào)用

大概就是 Service 中有一個(gè)方法 A,會(huì)內(nèi)部調(diào)用方法 B, 方法 A 沒(méi)有事務(wù)管理,方法 B 采用了聲明式事務(wù),通過(guò)在方法上聲明 Transactional 的注解來(lái)做事務(wù)管理。示例代碼如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@Service
public class RabbitServiceImpl implements RabbitService {
 
  @Autowired
  private RabbitDao rabbitDao;
  @Autowired
  private TortoiseDao tortoiseDao;
 
  @Override
  public Rabbit methodA(String name){
    return methodB(name);
  }
 
  @Transactional(propagation = Propagation.REQUIRED)
  public boolean methodB(String name){
    rabbitDao.insertRabbit(name);
    tortoiseDao.insertTortoise(name);
    return true;
  }
 
}

單元測(cè)試代碼如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class RabbitServiceImplTest {
 
  @Autowired
  private RabbitService rabbitService;
 
  // 事務(wù)未開(kāi)啟
  @Test
  public void testA(){
    rabbitService.methodA("rabbit");
  }
 
  // 事務(wù)開(kāi)啟
  @Test
  public void testB(){
    rabbitService.methodB("rabbit");
  }
}

從上一節(jié)中可以看到,聲明式事務(wù)是通通過(guò)AOP動(dòng)態(tài)代理實(shí)現(xiàn)的,這樣會(huì)產(chǎn)生一個(gè)代理類(lèi)來(lái)做事務(wù)管理,而目標(biāo)類(lèi)(service)本身是不能感知代理類(lèi)的存在的。

對(duì)于加了@Transactional注解的方法來(lái)說(shuō),在調(diào)用代理類(lèi)的方法時(shí),會(huì)先通過(guò)攔截器TransactionInterceptor開(kāi)啟事務(wù),然后在調(diào)用目標(biāo)類(lèi)的方法,最后在調(diào)用結(jié)束后,TransactionInterceptor 會(huì)提交或回滾事務(wù),大致流程如下圖:

完美解決Spring聲明式事務(wù)不回滾的問(wèn)題

總結(jié),在方法 A 中調(diào)用方法 B,實(shí)際上是通過(guò)“this”的引用,也就是直接調(diào)用了目標(biāo)類(lèi)的方法,而非通過(guò) Spring 上下文獲得的代理類(lèi),所以事務(wù)是不會(huì)開(kāi)啟的。

2. try...catch異常

在一段業(yè)務(wù)邏輯中對(duì)數(shù)據(jù)庫(kù)異常進(jìn)行了處理,使用了try...catch子句捕獲異常并throw了一個(gè)自定義異常,這種情況導(dǎo)致了事務(wù)未回滾,示例代碼如下:

?
1
2
3
4
5
6
7
8
9
10
@Transactional(propagation = Propagation.REQUIRED)
public boolean methodB(String name) throws BizException {
  try {
    rabbitDao.insertRabbit(name);
    tortoiseDao.insertTortoise(name);
  } catch (Exception e) {
    throw new BizException(ReturnCode.EXCEPTION.code, ReturnCode.EXCEPTION.msg);
  }
  return true;
}

BizException的定義如下:

?
1
2
3
public class BizException extends Exception {
  // 自定義異常
}

上面代碼中的聲明式事務(wù)在出現(xiàn)異常的時(shí)候,事務(wù)是不會(huì)回滾的。在代碼中我雖然捕獲了異常,但是同時(shí)我也拋出了異常,為什么事務(wù)未回滾呢?猜測(cè)是異常類(lèi)型不對(duì),于是開(kāi)始查詢(xún)?cè)颍戳薙pring的官方文檔,找到了答案。下面是翻譯自Spring官網(wǎng)。

17.5.3 聲明式事務(wù)的回滾

上一節(jié)中介紹了如何設(shè)置開(kāi)啟Spring事務(wù),一般在你的應(yīng)用的Service層代碼中設(shè)置,這一節(jié)將介紹在簡(jiǎn)單流行的聲明式事務(wù)中如何控制事務(wù)回滾。

在Spring FrameWork 的事務(wù)框架中推薦的事務(wù)回滾方法是,在當(dāng)前執(zhí)行的事務(wù)上下文中拋出一個(gè)異常。如果異常未被處理,當(dāng)拋出異常調(diào)用堆棧的時(shí)候,Spring FrameWork 的事務(wù)框架代碼將捕獲任何未處理的異常,然后并決定是否將此事務(wù)標(biāo)記為回滾。

在默認(rèn)配置中,Spring FrameWork 的事務(wù)框架代碼只會(huì)將出現(xiàn)runtime, unchecked 異常的事務(wù)標(biāo)記為回滾;也就是說(shuō)事務(wù)中拋出的異常時(shí)RuntimeException或者是其子類(lèi),這樣事務(wù)才會(huì)回滾(默認(rèn)情況下Error也會(huì)導(dǎo)致事務(wù)回滾)。在默認(rèn)配置的情況下,所有的 checked 異常都不會(huì)引起事務(wù)回滾。

注:Unchecked Exception包括Error與RuntimeException. RuntimeException的所有子類(lèi)也都屬于此類(lèi)。另一類(lèi)就是checked Exception。

你可以精確的配置異常類(lèi)型,指定此異常類(lèi)事務(wù)回滾,包括 checked 異常。下面的xml代碼片段展示了如何配置checked異常引起事務(wù)回滾,應(yīng)用自定義異常類(lèi)型:

?
1
2
3
4
5
6
<tx:advice id="txAdvice" transaction-manager="txManager">
 <tx:attributes>
 <tx:method name="get*" read-only="true" rollback-for="Exception"/>
 <tx:method name="*"/>
 </tx:attributes>
</tx:advice>

與其有同等作用的注解形式如下:

?
1
2
3
@Transactional(rollbackForClassName={"Exception"})
或者
@Transactional(rollbackFor={Exception.class})

在你遇到異常不想回滾事務(wù)的時(shí)候,同樣的你也可指定不回滾的規(guī)則,下面的一個(gè)例子告訴你,即使遇到未處理的 InstrumentNotFoundException 異常時(shí),Spring FrameWork 的事務(wù)框架同樣會(huì)提交事務(wù),而不回滾。

?
1
2
3
4
5
6
<tx:advice id="txAdvice">
 <tx:attributes>
 <tx:method name="updateStock" no-rollback-for="InstrumentNotFoundException"/>
 <tx:method name="*"/>
 </tx:attributes>
</tx:advice>

與其有同樣作用的注解形式如下:   

?
1
2
3
@Transactional(noRollbackForClassName={"InstrumentNotFoundException"})
或者
@Transactional(noRollbackFor={InstrumentNotFoundException.class})

還有更靈活的回滾規(guī)則配置方法,同時(shí)指定什么異?;貪L,什么異常不回滾。當(dāng)Spring FrameWork 的事務(wù)框架捕獲到一個(gè)異常的時(shí)候,會(huì)去匹配配置的回滾規(guī)則來(lái)決定是否標(biāo)記回滾事務(wù),使用匹配度最強(qiáng)的規(guī)則結(jié)果。因此,下面的配置例子表達(dá)的意思是,除了異常 InstrumentNotFoundException 之外的任何異常都會(huì)導(dǎo)致事務(wù)回滾。

?
1
2
3
4
5
<tx:advice id="txAdvice">
 <tx:attributes>
 <tx:method name="*" rollback-for="Throwable" no-rollback-for="InstrumentNotFoundException"/>
 </tx:attributes>
</tx:advice>

你也可以通過(guò)編程式的方式回滾一個(gè)事務(wù),盡管方法非常簡(jiǎn)單,但是也有非常強(qiáng)的代碼侵入性,使你的業(yè)務(wù)代碼和Spring FrameWork 的事務(wù)框架代碼緊密的綁定在一起,示例代碼如下:

?
1
2
3
4
5
6
7
8
public void resolvePosition() {
 try {
   // some business logic...
 } catch (NoProductInStockException ex) {
   // trigger rollback programmatically
   TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
 }
}

如果可能的話,強(qiáng)烈推薦您使用聲明式事務(wù)方式回滾事務(wù),對(duì)于編程式事務(wù),如果你強(qiáng)烈需要它,也是可以使用的,but its usage flies in the face of achieving a clean POJO-based architecture.(沒(méi)懂...)

看完官方文檔這節(jié)內(nèi)容找到了問(wèn)題的答案,原來(lái)是因?yàn)槲覀冏远x的異常不是 RuntimeException。我的解決辦法是,在注解@Transactional中添加 rollbackFor={BizException.class}。可能你會(huì)問(wèn)我為什么不將自定義異常修改為繼承RuntimeException,因?yàn)槲倚枰狟izException是一個(gè)checked 異常。

以上這篇完美解決Spring聲明式事務(wù)不回滾的問(wèn)題就是小編分享給大家的全部?jī)?nèi)容了,希望能給大家一個(gè)參考,也希望大家多多支持服務(wù)器之家。

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 久久99精品久久久久久园产越南 | 懂色av中文字幕一区二区三区 | 亚州av| 国产一区二区精品久久岳 | 亚洲欧美一级久久精品国产特黄 | 黄色免费网站在线观看 | 亚洲精品视频在线 | 亚洲激情在线观看 | 欧美日一区二区 | 免费 成 人 黄 色 | 韩国精品一区二区三区 | 免费国产一区 | 一区二区三区在线 | 综合五月| 欧美日韩精品一区二区公司 | 人成久久 | 国产模特私拍xxxx | 伦一区二区三区中文字幕v亚洲 | 欧美一级在线 | 啪啪伊人网 | 26uuu成人免费毛片 | 欧美国产日韩一区二区三区 | 中文字幕视频一区 | 国产精品免费视频观看 | 欧美久久精品 | 精品久久99 | 中日韩黄色大片 | 中文久久 | 亚洲精品国产成人 | t66y最新地址一地址二69 | av大片网| 亚洲一区二区中文 | 午夜色播 | 玖玖精品视频 | 国产在线观看二区 | 欧美视频在线免费 | 99爱在线观看 | 天天躁人人躁人人躁狂躁 | 成人免费视频播放 | 国产最新视频 | 亚洲精品电影在线观看 |