1. 程式人生 > >spring預設就能行,沒有就新建,有了就一起用一個事務(service呼叫service),一方錯都回滾

spring預設就能行,沒有就新建,有了就一起用一個事務(service呼叫service),一方錯都回滾

@Transactional 註解是用來指定介面、類或方法必須擁有事務語義的元資料。 如:“當一個方法開始呼叫時就開啟一個新的只讀事務,並停止掉任何現存的事務”。 預設的 @Transactional 設定如下:

  • 事務傳播設定是 PROPAGATION_REQUIRED

  • 事務隔離級別是 ISOLATION_DEFAULT

  • 事務是 讀/寫

  • 事務超時預設是依賴於事務系統的,或者事務超時沒有被支援。

  • 任何 RuntimeException 將觸發事務回滾,但是任何 checked Exception 將不觸發事務回滾

這些預設的設定當然也是可以被改變的。 @Transactional 註解的各種屬性設定總結如下:


Spring宣告式事務讓我們從複雜的事務處理中得到解脫。使得我們再也無需要去處理獲得連線、關閉連線、事務提交和回滾等這些操作。再也無需要我們在與事務相關的方法中處理大量的try…catch…finally程式碼。 

我們在使用Spring宣告式事務時,有一個非常重要的概念就是事務屬性。事務屬性通常由事務的傳播行為,事務的隔離級別,事務的超時值和事務只讀標誌組成。我們在進行事務劃分時,需要進行事務定義,也就是配置事務的屬性。 
Spring在TransactionDefinition介面中定義這些屬性,以供PlatfromTransactionManager使用, PlatfromTransactionManager是spring事務管理的核心介面。 

Java程式碼  收藏程式碼
  1. TransactionDefinition  
  2. public interface TransactionDefinition {  
  3.     int getPropagationBehavior();  
  4.     int getIsolationLevel();  
  5.     int getTimeout();  
  6.     boolean isReadOnly();  
  7. }  


getTimeout()方法,它返回事務必須在多少秒內完成。 
isReadOnly(),事務是否只讀,事務管理器能夠根據這個返回值進行優化,確保事務是隻讀的。 
getIsolationLevel()方法返回事務的隔離級別,事務管理器根據它來控制另外一個事務可以看到本事務內的哪些資料。 


在TransactionDefinition介面中定義了五個不同的事務隔離級別 
ISOLATION_DEFAULT 這是一個PlatfromTransactionManager預設的隔離級別,使用資料庫預設的事務隔離級別.另外四個與JDBC的隔離級別相對應 
ISOLATION_READ_UNCOMMITTED 這是事務最低的隔離級別,它充許別外一個事務可以看到這個事務未提交的資料。這種隔離級別會產生髒讀,不可重複讀和幻像讀。 
  例如: 
  Mary的原工資為1000,財務人員將Mary的工資改為了8000,但未提交事務 
Java程式碼  收藏程式碼
  1. Connection con1 = getConnection();  
  2. con.setAutoCommit(false);  
  3. update employee set salary = 8000 where empId ="Mary";  

與此同時,Mary正在讀取自己的工資 
Java程式碼  收藏程式碼
  1. Connection con2 = getConnection();  
  2. select  salary from employee where empId ="Mary";  
  3. con2.commit();  


Mary發現自己的工資變為了8000,歡天喜地! 
而財務發現操作有誤,而回滾了事務,Mary的工資又變為了1000 
Java程式碼  收藏程式碼
  1. //con1  
  2.   con1.rollback();  

像這樣,Mary記取的工資數8000是一個髒資料。 

ISOLATION_READ_COMMITTED  保證一個事務修改的資料提交後才能被另外一個事務讀取。另外一個事務不能讀取該事務未提交的資料。這種事務隔離級別可以避免髒讀出現,但是可能會出現不可重複讀和幻像讀。 

ISOLATION_REPEATABLE_READ  這種事務隔離級別可以防止髒讀,不可重複讀。但是可能出現幻像讀。它除了保證一個事務不能讀取另一個事務未提交的資料外,還保證了避免下面的情況產生(不可重複讀)。 

在事務1中,Mary 讀取了自己的工資為1000,操作並沒有完成 
Java程式碼  收藏程式碼
  1. con1 = getConnection();  
  2. select salary from employee empId ="Mary";  


在事務2中,這時財務人員修改了Mary的工資為2000,並提交了事務. 
Java程式碼  收藏程式碼
  1. con2 = getConnection();  
  2. update employee set salary = 2000;  
  3. con2.commit();  


在事務1中,Mary 再次讀取自己的工資時,工資變為了2000 
Java程式碼  收藏程式碼
  1. //con1  
  2. select salary from employee empId ="Mary";  


在一個事務中前後兩次讀取的結果並不致,導致了不可重複讀。 
使用ISOLATION_REPEATABLE_READ可以避免這種情況發生。 

ISOLATION_SERIALIZABLE 這是花費最高代價但是最可靠的事務隔離級別。事務被處理為順序執行。除了防止髒讀,不可重複讀外,還避免了幻像讀。 

目前工資為1000的員工有10人。 
事務1,讀取所有工資為1000的員工。 
Java程式碼  收藏程式碼
  1. con1 = getConnection();  
  2. Select * from employee where salary =1000;  
共讀取10條記錄 

這時另一個事務向employee表插入了一條員工記錄,工資也為1000 
Java程式碼  收藏程式碼
  1. con2 = getConnection();  
  2. Insert into employee(empId,salary) values("Lili",1000);  
  3. con2.commit();  


事務1再次讀取所有工資為1000的員工 
Java程式碼  收藏程式碼
  1. //con1  
  2. select * from employee where salary =1000;  


共讀取到了11條記錄,這就產生了幻像讀。 
ISOLATION_SERIALIZABLE能避免這樣的情況發生。但是這樣也耗費了最大的資源。 

getPropagationBehavior()返回事務的傳播行為,由是否有一個活動的事務來決定一個事務呼叫。 

在TransactionDefinition介面中定義了七個事務傳播行為。 

PROPAGATION_REQUIRED 如果存在一個事務,則支援當前事務。如果沒有事務則開啟一個新的事務。 

Java程式碼  收藏程式碼
  1. //事務屬性 PROPAGATION_REQUIRED  
  2. methodA{  
  3. ……  
  4. methodB();  
  5. ……  
  6. }  
  7. //事務屬性 PROPAGATION_REQUIRED  
  8. methodB{  
  9.    ……  
  10. }  

使用spring宣告式事務,spring使用AOP來支援宣告式事務,會根據事務屬性,自動在方法呼叫之前決定是否開啟一個事務,並在方法執行之後決定事務提交或回滾事務。 

單獨呼叫methodB方法 
Java程式碼  收藏程式碼
  1. main{  
  2.   metodB();  
  3. }  

相當於 
Java程式碼  收藏程式碼
  1. Main{  
  2. Connection con=null;  
  3.    rry{  
  4.       con = getConnection();  
  5.       con.setAutoCommit(false);  
  6. //方法呼叫  
  7. methodB();  
  8. //提交事務  
  9. con.commit();  
  10. }  
  11. Catch(RuntimeException ex){  
  12.   //回滾事務  
  13.   con.rollback();    
  14. }  
  15. finally{  
  16.   //釋放資源  
  17.   closeCon();  
  18. }  
  19. }  

Spring保證在methodB方法中所有的呼叫都獲得到一個相同的連線。在呼叫methodB時,沒有一個存在的事務,所以獲得一個新的連線,開啟了一個新的事務。 

單獨呼叫MethodA時,在MethodA內又會呼叫MethodB. 

執行效果相當於 
Java程式碼  收藏程式碼
  1. main{  
  2.    Connection con = null;  
  3.    try{  
  4.       con = getConnection();  
  5.       methodA();  
  6.       con.commit();  
  7. }  
  8. cathc(RuntimeException ex){  
  9.  con.rollback();  
  10. }  
  11. finally{  
  12.   closeCon();  
  13. }   
  14. }  

呼叫MethodA時,環境中沒有事務,所以開啟一個新的事務. 
當在MethodA中呼叫MethodB時,環境中已經有了一個事務,所以methodB就加入當前事務。 

PROPAGATION_SUPPORTS 如果存在一個事務,支援當前事務。如果沒有事務,則非事務的執行。但是對於事務同步的事務管理器,PROPAGATION_SUPPORTS與不使用事務有少許不同。 

Java程式碼  收藏程式碼
  1. //事務屬性 PROPAGATION_REQUIRED   
  2. methodA(){  
  3.   methodB();  
  4. }  
  5. //事務屬性 PROPAGATION_SUPPORTS   
  6. methodB(){  
  7.   ……  
  8. }  

單純的呼叫methodB時,methodB方法是非事務的執行的。 
當呼叫methdA時,methodB則加入了methodA的事務中,事務地執行。 

PROPAGATION_MANDATORY 如果已經存在一個事務,支援當前事務。如果沒有一個活動的事務,則丟擲異常。 

Java程式碼  收藏程式碼
  1. //事務屬性 PROPAGATION_REQUIRED   
  2. methodA(){  
  3.   methodB();  
  4. }  
  5. //事務屬性 PROPAGATION_MANDATORY   
  6. methodB(){  
  7.   ……  
  8. }  

當單獨呼叫methodB時,因為當前沒有一個活動的事務,則會丟擲異常 
throw new IllegalTransactionStateException("Transaction propagation 'mandatory' but no existing transaction found"); 

當呼叫methodA時,methodB則加入到methodA的事務中,事務地執行。 

PROPAGATION_REQUIRES_NEW 總是開啟一個新的事務。如果一個事務已經存在,則將這個存在的事務掛起。 

Java程式碼  收藏程式碼
  1. //事務屬性 PROPAGATION_REQUIRED   
  2. methodA(){  
  3.   doSomeThingA();  
  4. methodB();  
  5. doSomeThingB();  
  6. }  
  7. //事務屬性 PROPAGATION_REQUIRES_NEW   
  8. methodB(){  
  9.   ……  
  10. }  

當單獨呼叫methodB時,相當於把methodb宣告為REQUIRED。開啟一個新的事務,事務地執行。 

當呼叫methodA時 
Java程式碼  收藏程式碼
  1. main(){  
  2.   methodA();  
  3. }  
情況有些大不一樣.相當於下面的效果。 
Java程式碼  收藏程式碼
  1. main(){  
  2.  TransactionManager tm = null;  
  3. try{  
  4.   //獲得一個JTA事務管理器  
  5.    tm = getTransactionManager();  
  6.    tm.begin();//開啟一個新的事務  
  7.    Transaction ts1 = tm.getTransaction();  
  8.    doSomeThing();  
  9.    tm.suspend();//掛起當前事務  
  10.    try{  
  11.      tm.begin();//重新開啟第二個事務  
  12.      Transaction ts2 = tm.getTransaction();  
  13.      methodB();  
  14.      ts2.commit();//提交第二個事務  
  15.    }  
  16.   Catch(RunTimeException ex){  
  17.      ts2.rollback();//回滾第二個事務  
  18.   }  
  19.   finally{  
  20.     //釋放資源  
  21.   }  
  22.    //methodB執行完後,復恢第一個事務  
  23.    tm.resume(ts1);  
  24. 相關推薦

    spring預設沒有新建起用一個事務service呼叫service一方

    @Transactional 註解是用來指定介面、類或方法必須擁有事務語義的元資料。 如:“當一個方法開始呼叫時就開啟一個新的只讀事務,並停止掉任何現存的事務”。 預設的 @Transactional 設定如下: 事務傳播設定是 PROPAGATION_REQUIRE

    SQL程式設計:group 不用合併結果字串 ---> group_concat函式

    1、表結構    create table tt(id int,v varchar(30));              insert into tt values(1,'a'),(1,'b'),(2,'b'),(2,'c'),(2,'b'),(2,'a'),(3,'a');              mys

    SQL程式設計:模糊表關聯不求人 ---> concat + like

    1、表的結構:​create table A(proj_dept varchar(30)); create table B(dept_id int,dept_name varchar(30));

    程式設計師不加班領導:不想幹

    在工作中,加班不是目的,加班是為了完成工作,當員工能在正常上班時間內完成工作,無需加班,這時候作為領導也就沒有必要讓其留下來加班。 然而也有一些公司領導只看員工加不加班,就有一領導經過幾天的觀察,發現新來的幾名程式設計師每天晚上不到八點就早早的下班走了,對此這名領導很生氣,想管管這群新來

    樹狀陣列Binary Indexed Tree看這

    定義 根據維基百科的定義: A Fenwick tree or binary indexed tree is a data structure that can efficiently update elements and calculate pr

    算法整理php語言完成持續更中......

    == 排序 pre cnblogs 部分 兩個 div function col 一下所有實例中,均在同一個方法中,所以算法使用內部函數完成 歸並排序 1 public function test1Action () { 2 $tmp = 0; 3

    內核運時數據結構的操作啟用路由功能sysctl內核設置命令

    etc class 方式 con ipv4 lin spa 系統 ont LINUX系統運行時,內核數據結構數據的修改,系統提供了統一抽象的文件操作接口(命名空間操作接口)比如啟用路由功能echo 1 > proc/sys/net/ipv4/ip-forward/

    Bootstrap3基礎 row 柵格系統非響應式1最多12列

    nta blue 屏幕 視頻 鍛煉 cast 思考 3.3 系統 禮悟:   公恒學思合行悟,尊師重道存感恩。葉見尋根三返一,江河湖海同一體。 虛懷若谷良心主,願行無悔給最苦。讀書鍛煉養身心,誠勸且行且珍惜。    i

    ireport報表製作一個欄位顯示的資料太多時資料過長則需要自動換

    1、當一個欄位顯示的資料太長,一個表格放不下,則需要自動換行,選中要更改的表格(要顯示動態內容的欄位),設定屬性Stretch with overflow 為鉤選狀態。 未勾選之前:   勾選之後:   2、但是,表格出現斷層的情況

    VS程式設計使用替換的方式將程式碼中字串以某字元以標誌常以逗號進行換分行顯示。相當於按回車鍵

    1、從一行,通過替換變成多行,相當於按回車  替換之前: 替換之後:   步驟:  1,選中要替換的程式碼 2、按ctrl + H 兩個鍵,調出替換視窗, 3、在替換視窗進行如下設定: 4、點選替換所有按鈕

    extjs3 分頁操作帶查詢條件獲取頁碼、開始、分頁大小

    一、分頁操作 extjs3.x版本做分頁操作時,只需配置PagingToolbar 即可,總的來說還是比較方便的,但是預設情況下是不能進行帶查詢條件的分頁操作的,如何解決呢? //xxx表示檔名,xxx.js xxx.prototype.grid=function(){

    spring cloud 入門【容錯機制二通過方法容錯這個方法是面向介面程式設計我覺得更好一些】

    程式碼結構如下:   pom 檔案中新增  hystrix <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>

    App Store Connect顯示app已經上架可供銷售但在App Store中沒有實時更新

    記得去年(2016年)的時候,上線的時候,基本上稽核通過的時間平均是3天左右,有時候在你很急的時候,甚至會讓你等到一週左右;但是最近發現上線很快,最近(2017年11月)提交,即使是晚上22:00左右提交,第二天一早,一登入自己的開發者賬號會看到“稽核通過”的字

    編寫一個函式 reverse_string(char * string)遞迴實現將引數字串中的字元反向排列。 要求不使用C函式庫中的字串操作函式

    #include<stdio.h> #include<stdlib.h> int str(char *string) { int n = 0; while (*string) { n++; string++; } return n; } void rever

    天書般的gcc嵌入彙編內聯彙編似乎沒有選擇硬著腦瓜皮學下去吧!

     執行結果:(參考書籍《LInux核心完全註釋》,趙炯編著) 仿照手中自己編寫的程式碼: #include <stdio.h> #define mystrcpy(dest, source) \ ({ \ register char *mydest __asm__

    雞和兔關在一個籠子裡2只腳4只腳沒有例外。已知現在可以看到籠子裡m個頭和n只腳求雞和兔子各多少隻?輸出組資料

    #include<stdio.h>int main(){ int m,n;           //m個頭,n個腳。 int x,y;              //x只雞,y只兔。 scanf("%d%d",&m,&n); for(x=0;x&l

    利用Python抵禦外星人的入侵Python小遊戲零基礎也寫!

    利用Python抵禦外星人的入侵(Python小遊戲),零基礎也能寫! 導語 寫了個低配版的外星人入侵小遊戲來作為19年的第一更吧讓我們愉快地開始吧原始碼私信小編加群:700341555獲取,還可獲取Python入門學習資料! 利用Python抵禦外星人的入侵(Python小

    一個由26字母中的幾個組成的字串可出現重複再插入一個字母組成多少種字串

    小明有26種遊戲海報,用小寫字母a-z表示,小明會把遊戲海報裝訂成冊(可能有重複的海報),冊子可以用一個字串來表示,每個字元就表示對應的海報,例如abcdea,小明現在想做一些“特別版”,然後賣掉,特別版就是會從所有海報(26種)中隨機選一張,加入到冊子的任意一

    JS獲取當前時間YYYY-MM-DD element顯示預設當前時間顯示預設昨天顯示預設上個月

    進來的隨便看看,或許有幫助 vue+element-ui   datepicker 設定預設日期 用的框架是vue+element-ui ,以下是時間控制元件 <el-form-item label="月份"> <el-date-picker v-m

    java 訪問許可權private,預設預設包許可權protected繼承訪問許可權public的個人理解

    package pack1; /** * Created by Kodulf on 2017/4/5. */ public class FanWenCeShi { /**