Spring事務總結---傳播級別以及REQUIRED_NEW及NESTED的使用場景(贊)
摘要: 在工作中時常需要用到Spring的事務,每次遇到問題都google十分浪費時間,不妨自己總結一下做個記錄,希望以後遇到問題的時候能在自己的記錄中找到解答。:)
超過了字數限制,強行被分割。。。。
三、Spring事務的傳播性與隔離級別
Spring它對JDBC的隔離級別作出了補充和擴充套件,其提供了7種事務傳播行為。(通俗解釋原址)
1、PROPAGATION_REQUIRED:預設事務型別,如果沒有,就新建一個事務;如果有,就加入當前事務。適合絕大多數情況。
2、PROPAGATION_REQUIRES_NEW:如果沒有,就新建一個事務;如果有,就將當前事務掛起。
3、PROPAGATION_NESTED:如果沒有,就新建一個事務;如果有,就在當前事務中巢狀其他事務。
4、PROPAGATION_SUPPORTS:如果沒有,就以非事務方式執行;如果有,就使用當前事務。
5、PROPAGATION_NOT_SUPPORTED:如果沒有,就以非事務方式執行;如果有,就將當前事務掛起。即無論如何不支援事務。
6、PROPAGATION_NEVER:如果沒有,就以非事務方式執行;如果有,就丟擲異常。
7、PROPAGATION_MANDATORY:如果沒有,就丟擲異常;如果有,就使用當前事務。
第4、5、6、7種特性很好理解了,主要是前三種特性比較容易混淆或用錯。
那麼PROPAGATION_REQUIRED、PROPAGATION_REQUIRES_NEW、PROPAGATION_NESTED的區別在哪呢?
什麼有就建立一個什麼巢狀掛起,很明顯不如一些使用場景清晰,那就直接上例子。
先定義一些實驗性的方法。(例子程式碼:https://git.oschina.net/sluggarddd/spring-tx-demo.git)
@Service
public class IUserServiceImpl implements IUserService {
@Resource
IUserDAO userDAO;
@Resource
IUserService2 userService2;
//不帶事務的方法
public void funNone() throws Exception {
save(new UserEntity("zhw"));
}
//啟動預設事務的方法
@Transactional(propagation = Propagation.REQUIRED)
public void funRequire() throws Exception {
save(new UserEntity("wlj"));
}
//啟動預設事務的方法
@Transactional(propagation = Propagation.REQUIRED)
public void funRequire2() throws Exception {
save(new UserEntity("shifang"));
}
//啟動預設事務的方法,丟擲RuntimeException
@Override
@Transactional(propagation = Propagation.REQUIRED)
public void funRequireException() throws Exception {
save(new UserEntity("max"));
throwExcp();
}
//啟動巢狀事務的方法
@Transactional(propagation = Propagation.NESTED)
public void funNest() throws Exception {
save(new UserEntity("yunxinghe"));
}
//啟動巢狀事務的方法,但會丟擲異常
@Override
@Transactional(propagation = Propagation.NESTED)
public void funNestException() throws Exception {
save(new UserEntity("edward"));
throwExcp();
}
//REQUIRES_NEW事務的方法
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void funRequireNew() throws Exception {
save(new UserEntity("kb"));
}
//REQUIRES_NEW事務的方法,但會丟擲異常
@Override
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void funRequireNewException() throws Exception {
save(new UserEntity("laura"));
throwExcp();
}
//丟擲異常
private void throwExcp() throws Exception {
throw new RuntimeException("boom");
}
//儲存資料
public int save(UserEntity userEntity) throws Exception {
userDAO.save(userEntity);
return userEntity.getId();
}
}
我們定義了兩個映象(就是一樣的Serivce)分別是UserService,UserService2,是一樣的,只是相互呼叫,不重複上程式碼。
@Override
@Transactional
public void fun1() throws Exception {
//資料庫操作
funNone();
//呼叫另一個service的方法
userService2.funNest();
//當呼叫另一個Service的method的時候,想要將他的事務加到現在這個事務中,很可能自然而然想到了巢狀
//這麼想就錯了,Required的定義裡已經說明了如果沒有,就新建一個事務;如果有,就加入當前事務。
//那麼直接使用Required就滿足需求
//這樣在方法中任何地方發生unchecked異常將觸發整個方法的回滾
//而Nested的使用場景下面再介紹
}
NESTED事務使用場景
@Override
@Transactional
public void fun2() throws Exception {
//巢狀事務的使用場景
funNone();
try {
//當所呼叫的方法為NESTED事務,該事務的回滾可以不影響到呼叫者的事務
//當然如果沒有catch exception,異常冒泡而出,就將觸發呼叫者事務的回滾
userService2.funNestException();
} catch (Exception e) {
//do something
}
userService2.funRequire();
}
//執行結果:
//userService2.funNestException()被回滾
//其他插入成功
外部的異常能觸發所呼叫的NESTED事務回滾
@Override
@Transactional
public void fun3() throws Exception {
//巢狀事務的使用場景
funNone();
try {
//呼叫的事務為NESTED事務的方法
userService2.funNest();
} catch (Exception e) {
//do something
}
userService2.funRequire();
//此時在呼叫者處,觸發一個unchecked異常
throwExcp();
//此時會發現包括呼叫的userService2.funNest()也被回滾了
//也就是說,當呼叫的方法是NESTED事務,該方法丟擲異常如果得到了處理(try-catch),那麼該方法發生異常不會觸發整個方法的回滾
//而呼叫者出現unchecked異常,卻能觸發所呼叫的nested事務的回滾.
}
//執行結果
//全部被回滾
REQUIRES_NEW的使用場景
@Override
@Transactional
public void fun4() throws Exception {
//而REQUIRES_NEW,當被呼叫時,就相當於暫停(掛起)當前事務,先開一個新的事務去執行REQUIRES_NEW的方法,如果REQUIRES_NEW中的異常得到了處理
//那麼他將不影響呼叫者的事務,同時,呼叫者之後出現了異常,同樣也不會影響之前呼叫的REQUIRES_NEW方法的事務.
//不會回滾
funNone();
try {
//當異常得到處理,外部不會觸發回滾
userService2.funRequireNewException();
} catch (Exception e) {
}
}
//執行結果
//funNone()正常持久化
// userService2.funRequireNewException()回滾
@Override
@Transactional
public void fun5() throws Exception {
//資料庫操作
funNone();
//呼叫RequireNew型別事務的方法,呼叫者的異常回滾不會影響到它
userService2.funRequireNew();
//資料庫操作
funNone();
//丟擲unchecked異常,觸發回滾
throwExcp();
}
//執行結果
//userService2.funRequireNew();正常持久化
//其他操作被回滾
如果呼叫的是REQUIRED型別,即使處理了被呼叫方法丟擲的異常仍然會被回滾。
@Override
@Transactional
public void fun6() throws Exception {
funNone();
try {
//當呼叫的是Required時,就算異常被處理了,整個方法也將會回滾
userService2.funRequireException();
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
//執行結果
//被回滾
總結:附上一段我覺得很好的總結(Jurgen Hoeller原話翻譯)(翻譯從這裡拷的)
PROPAGATION_REQUIRES_NEW 啟動一個新的, 不依賴於環境的 "內部" 事務. 這個事務將被完全 commited 或 rolled back 而不依賴於外部事務, 它擁有自己的隔離範圍, 自己的鎖, 等等. 當內部事務開始執行時, 外部事務將被掛起, 內務事務結束時, 外部事務將繼續執行.
另一方面, PROPAGATION_NESTED 開始一個 "巢狀的" 事務, 它是已經存在事務的一個真正的子事務. 潛套事務開始執行時, 它將取得一個 savepoint. 如果這個巢狀事務失敗, 我們將回滾到此 savepoint. 潛套事務是外部事務的一部分, 只有外部事務結束後它才會被提交.
由此可見, PROPAGATION_REQUIRES_NEW 和 PROPAGATION_NESTED 的最大區別在於, PROPAGATION_REQUIRES_NEW 完全是一個新的事務, 而 PROPAGATION_NESTED 則是外部事務的子事務, 如果外部事務 commit, 潛套事務也會被 commit, 這個規則同樣適用於 roll back.
四、Spring事務自我呼叫的坑
當Spring的事務在同一個類時,它的自我呼叫時事務就完犢子了!(不知道這個的時候被坑出翔)
當同一個類的方法之間事務發生自我呼叫,其事務的特性將失效。
@Override
@Transactional
public void fun7() throws Exception {
funRequire();
try {
//本應回滾這個方法,但發生了異常並沒有回滾
funNestException();
} catch (Exception e) {
System.out.println(e.getMessage());
}
funRequire();
}
例如上面Nested的特性就沒了,其執行結果是三個發生insert的語句都成功插入到資料庫了。
原因我自己肯定沒別人總結的好(連問題都說的不太清楚),就直接放連結了(原因點此),不想看的直接上解決方法。
1、首先引入
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>${aspectj.version}<ersion>
</dependency>
2、開啟暴露AOP代理到ThreadLocal支援
<aop:aspectj-autoproxy proxy-target-class="true" expose-proxy="true"/>
3、在自我呼叫的時候這麼寫
fun8() Exception {
((IUserService) AopContext.()).funRequire();
{
((IUserService) AopContext.()).funNestException();
} (Exception e) {
System..println(e.getMessage());
}
((IUserService) AopContext.()).funRequire();
}
這樣,就能讓配置在該方法上的事務發揮應有的特性啦。
原因我也來總結一句,因為開啟事務和事務回滾,實際這個過程是aop代理幫忙完成的,當呼叫一個方法時,他會先檢查時候有事務,有則開啟事務,當呼叫本類的方法是,他並沒有將其視為proxy呼叫,而是方法的直接呼叫,所以也就沒有檢查該方法是否含有事務這個過程,那麼他生命的事務也就不成立了。
另外,除了這個解決方法,開濤大神那個部落格還提供了其他解決方式,可以根據自己的需求選擇。
總結一下對自己理解還是蠻有幫助的,希望也能稍微幫到有需要的人。
完。
相關推薦
spring的事務傳播行為 Spring事務總結---傳播級別以及REQUIRED_NEW及NESTED的使用場景(贊)
總結:附上一段我覺得很好的總結(Jurgen Hoeller原話翻譯)(翻譯從這裡拷的) PROPAGATION_REQUIRES_NEW 啟動一個新的, 不依賴於環境的 "內部" 事務. 這
Spring事務總結---傳播級別以及REQUIRED_NEW及NESTED的使用場景
三、Spring事務的傳播性與隔離級別 Spring它對JDBC的隔離級別作出了補充和擴充套件,其提供了7種事務傳播行為。(通俗解釋原址) 1、PROPAGATION_REQUIRED:預設事務型別,如果沒有,就新建一個事務;如果有,就加入當前事務。適合絕大
Spring事務總結---傳播級別以及REQUIRED_NEW及NESTED的使用場景(贊)
摘要: 在工作中時常需要用到Spring的事務,每次遇到問題都google十分浪費時間,不妨自己總結一下做個記錄,希望以後遇到問題的時候能在自己的記錄中找到解答。:) 超過了字數限制,強行被分割。。。。 三、Spring事務的傳播性與隔離級別 Spring它對JDB
Spring事務的傳播級別
### 一、簡單說明 傳播屬性|描述 -|- PROPAGATION_REQUIRED|如果當前沒有事務,就建立一個事務,如果當前存在事務,就加入該事務。 PROPAGATION_REQUIRED_NEW|當前的方法必須啟動新事務,並在它自己的事務內執行,不管是否存著事務,都開啟新事務。 PROPAGATIO
spring事務的傳播屬性和事務隔離級別及配置事務(註解方式)
一、Propagation (事務的傳播屬性) Propagation : key屬性確定代理應該給哪個方法增加事務行為。這樣的屬性最重要的部份是傳播行為。有以下選項可供使用: PROPAGATION_REQUIRED--支援當前事務,如果當前沒有事務,就新建一個事務。這是最常見的選擇。 PROPAG
Java知識點集合05--- Spring的兩大核心&Spring事務的傳播特性&隔離級別&ORM&ibatis和Hibernate&Hibernate對映物件狀態
Spring的兩大核心 spring是J2EE應用程式框架,是輕量級的IOC和AOP容器框架(相對於EJB ),針對javabean生命週期進行管理的親兩級容器。 IOC(控制反轉Invesion of control)或DI(依賴注入 Dependency
Spring事務的傳播特性和隔離級別(持續更新中)
Spring TransactionDefinition介面中定義了事務的隔離級別和事務的傳播特性 傳播特性 例子: class ClassA{ method(){ //邏輯處理1 classB.
spring事務五大隔離級別、七大傳播行為
1.事務的定義:事務是指多個操作單元組成的合集,多個單元操作是整體不可分割的,要麼都操作不成功,要麼都成功。其必須遵循四個原則(ACID)。 原子性(Atomicity):即事務是不可分割的最小工作單元,事務內的操作要麼全做,要麼全不做;一致性(Consistency):
Spring 事務管理 事務的傳播級別
例子:對於預設的傳播級別 REQUIRED 的測試首先對於 REQUIRED 的解釋如下: 預設事務型別,如果沒有,就新建一個事務;如果有,就加入當前事務,也就是大家都使用同一個事務模型,只要有一個發生了異常,那麼整個事務都會回滾。其中對於發生異常導致事務回滾需要注重理解,否
Spring事務的傳播行為、隔離級別、回滾、只讀和過期
事務的傳播性- 當事務的方法被另一個事務的方法呼叫時,必須指定事務應該如何傳播。如:方法可能繼續在現有的事務中執行,也可能開啟一個新的事務,並在自己的事務中執行。- 事務的傳播行為可以由傳播屬性指定。Spring定義了7種傳播行為:required:如果有事務在執行,當前的方
Spring 事務的隔離級別和傳播行為的理解
一、Spring 事務的隔離級別 在瞭解Spring事務隔離級別前,先弄清楚以下概念: 髒讀:髒讀發生在一個事務讀取了被另一個事務改寫但還未提交的資料時。如果這些改變在稍後被回滾,那麼之前的事務讀取的到資料就是無效的。 不可重複讀:不
事務的傳播無效,required_new無效,動態代理給spring事務傳播留下的坑
事務的傳播級別 七種傳播級別 propagation_requierd:如果當前沒有事務,就新建一個事務,如果已存在一個事務中,加入到這個事務中,這是最常見的選擇。(預設) propagation_supports:支援當前事務,如果沒有當前事務,就以
Spring事務配置的五種方式及事務傳播相關(不看後悔,一看必懂!)
原文:http://blog.csdn.net/hjm4702192/article/details/17277669 前段時間對Spring的事務配置做了比較深入的研究,在此之間對Spring的事務配置雖說也配置過,但是一直沒有一個清楚的認識。通過這次的學習發覺Sprin
Spring事務總結---事務概述及Spring事務的基本使用(完整)
一、事務概述 這一節內容純粹是為了寫而寫的,權當溫習資料庫知識和熟悉下怎麼寫部落格了,誰讓自己菜呢。:) 看了許多別的部落格和資料,事務兩個字都快不認識了,那麼其實事務的概念很簡單,可以理解為一件事情,在計算機裡,它就是一個操作序列。 它相比於普通的事情不同的是,它必須服從ISO/IEC指
通過TransactionDefinition介面來學習spring事務的隔離級別和傳播特性(4.3.4版本)
通過spring官方包中帶的原始碼來看spring的事務的5中隔離級別和7種傳播特性; 原始碼如下: /* * Copyright 2002-2015 the original author or authors. * * Licensed under th
spring 事務的傳播特性
nal 調用 ransac 提交 port 文件 action com pre 1.聲明式事物中,一個類serviceA的方法test1()調用另一個類serviceB的方法test2() 要是serviceB的test2()事務配置在xml文件中為REQUIRED,又
spring事務的隔離級別(透徹理解)
wired pan 用戶 出現 不同的 而且 之前 () b- 1.spring 事務這個東西,是輪子,每個service,都需要用到。所以幹脆就做在框架層實現。 2.spring是怎麽給你的service方法加事務的呢?jdk動態代理,會針對每個service類裏
Spring事務的隔離級別
多次 結果 結束 說明 div edit 對數 正在 gb2312 1. ISOLATION_DEFAULT: 這是一個 PlatfromTransactionManager 默認的隔離級別,使用數據庫默認的事務隔離級別. 另外四個與 JDBC的隔離級別相對
Spring事務處理的實現:Spring事務總結
這篇我想對Spring事務機制進行一次總結,總結的方式也和AOP類似那就是使用圖解的方式。首先我們需要對我們事務的AOP機制進行初始化,也就是宣告要對那些方法(切面)進行增強,這裡涉及到了TransactionInterceptor攔截器鏈的生成。 接著書上講述了事務處理配置的讀入。
spring 事務的隔離級別
spring有五大隔離級別: ISOLATION_DEFAULT:用底層資料庫的預設隔離級別,資料庫管理員設定什麼就是什麼 ISOLATION_READ_UNCOMMITTED(未提交讀):最低隔離級別、事務未提交前,就可被其他事務讀取(會出現幻讀、髒讀、不可重複讀) ISOLA