日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

你了解过Spring支持的常用数据库事务传播属性和隔离级别吗?来一起看看吧!!!

發布時間:2025/3/19 javascript 48 豆豆
生活随笔 收集整理的這篇文章主要介紹了 你了解过Spring支持的常用数据库事务传播属性和隔离级别吗?来一起看看吧!!! 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

上次偶然間看到這個知識點,發現自己有所欠缺,就來進行查漏補缺,沒法實在是卷的厲害啊。😭

那么不知道你對于Spring支持的常用數據庫事務傳播屬性和隔離級別了解的怎么樣呢?要不要一起復習復習勒😁

很喜歡一句話:“八小時內謀生活,八小時外謀發展”

共勉👩?💻


描述:進來先看看風景啦,要相信會有光的哦

Spring支持的常用數據庫事務傳播屬性和隔離級別

    • 一、事務傳播屬性
      • 前言:
      • 概念:
    • 二、事務傳播代碼演示
      • 2.1、數據庫表:
      • 2.2、代碼
      • 2.3測試:
    • 三、數據庫事務隔離級別
      • 3.1、數據庫事務并發問題
      • 3.2 數據庫隔離性
      • 3.3、測試
    • 四、自言自語

一、事務傳播屬性

前言:

對于數據庫事務ACID(原子性、一致性、隔離性、持久性)性質我想大家都是知道的,這里就不寫了😁

我們都知道用事務是為了保證數據庫的完整性,保證成批的 SQL 語句要么全部執行,要么全部不執行。

但是如果一個方法嵌套關聯著其他方法勒,這該怎么算呢?當前方法及關聯方法都有事務呢,或者只是其中某幾個有事務,該用誰的呢?

概念:

事務的傳播行為:一個方法運行在一個開啟了事務的方法上時,當前方法是使用原來的事務還是開啟一個新的事務。

通過 @Transaction 注解中 propagation 來設置事務傳播行為。其中

事務傳播行為總共有以下七種:

傳播屬性描述
REQUIRED業務方法需要在一個事務中運行。如果方法運行時,已經處在一個事務中,那么加入到該事務,否則為自己創建一個新的事務。(默認值)
NOT_SUPPORTED聲明方法不需要事務。如果方法沒有關聯到一個事務,容器不會為它開啟事務。如果方法在一個事務中被調用,該事務會被掛起,在方法調用結束后,原先的事務便會恢復執行。
應用場景:有數據操作處理(需要事務)+異步調用(不需要事務,掛起)
REQUIRESNEW不管是否存在事務,業務方法總會為自己發起一個新的事務。如果方法已經運行在一個事務中,則原有事務會被掛起,新的事務會被創建,直到方法執行結束,新事務才算結束,原先的事務才會恢復執行。
MANDATORY該屬性指定業務方法只能在一個已經存在的事務中執行,業務方法不能發起自己的事務。如果業務方法在沒有事務的環境下調用,容器就會拋出例外。
SUPPORTS這一事務屬性表明,如果業務方法在某個事務范圍內被調用,則方法成為該事務的一部分。如果業務方法在事務范圍外被調用,則方法在沒有事務的環境下執行。
NEVER指定業務方法絕對不能在事務范圍內執行。如果業務方法在某個事務中執行,容器會拋出例外,只有業務方法沒有關聯到任何事務,才能正常執行。
例:應用于報表統計程序
NESTED如果一個活動的事務存在,則運行在一個嵌套的事務中. 如果沒有活動事務, 則按REQUIRED屬性執行.啟用一個新的事務, 這個事務擁有多個可以回滾的保存點。內部事務的回滾不會對外部事務造成影響。它只對DataSourceTransactionManager事務管理器起效

下面寫了一個小demo來讓理解更加快捷一些哈。

二、事務傳播代碼演示

2.1、數據庫表:

注意:account表中 balance字段是設置為無符號的(即不能為負數)。

2.2、代碼

項目就是普通Spring項目

模擬的是買書的一個過程,賬戶余額不足,但是一次買多本的情況,一起付款。

在其中再測試事務傳播行為的不同,來看數據的變化。

初始代碼:

public interface CashierService {void checkout(int userId, List<Integer> isbns); } @Service public class CashierServiceImpl implements CashierService {@AutowiredBookShopService bookShopService;@Transactional@Overridepublic void checkout(int userId, List<Integer> isbns) {for (Integer isbn : isbns) {// 調用bookShopService 買書的方法bookShopService.purchase(userId, isbn);}} } public interface BookShopService {void purchase(int userId,int isbn); } @Service public class BookShopServiceImpl implements BookShopService {@AutowiredBookShopMapper bookShopMapper;@Transactional@Overridepublic void purchase(int userId, int isbn) {// 獲取要買的圖書double bookPrice = bookShopMapper.getBookPriceByIsbn(isbn);// 更新圖書的庫存bookShopMapper.updateBootStock(isbn);// 更新用戶的余額bookShopMapper.updateAccountBalance(userId,bookPrice);} }

mapper層代碼

@Mapper @Repository public interface BookShopMapper {@Select("select price from book where isbn=#{isbn}")double getBookPriceByIsbn(int isbn);@Update("update book_stock set stock=stock-1 where isbn=#{isbn}")void updateBootStock(int isbn);@Update("update account set balance=balance-#{bookPrice} where id=#{userId}")void updateAccountBalance(@Param("userId") int userId, double bookPrice); }

2.3測試:

測試一:默認事務傳播行為

我們在void checkout(int userId, List<Integer> isbns) 和void purchase(int userId, int isbn)上都加了 @Transactional

目前賬戶為 100元,兩本書的價格分別為 60和50 ,因為我們的付款過程是 使用循環 購買的,你說我們會買到一本還是一本都買不到呢?

@Autowired CashierService cashierService; @Test void test(){List<Integer> isbns = new ArrayList<>();// 加購兩本書isbns.add(1001);isbns.add(1002);// 結賬cashierService.checkout(1,isbns); }

答案當然是一本都買不到,因為@Transactional 注解 ,默認事務的傳播屬性是:REQUIRED,即業務方法需要在一個事務中運行。如果方法運行時,已經處在一個事務中,那么加入到該事務,否則為自己創建一個新的事務。所以實際上 void purchase(int userId, int isbn)其實和調用它的方法用的同一個事務。簡單畫個圖:

測試二:測試 -->REQUIRES_NEW屬性

其他代碼未改變,僅在purchase 上的注解上加了點東西@Transactional(propagation = Propagation.REQUIRES_NEW).

REQUIRES_NEW: 不管是否存在事務,業務方法總會為自己發起一個新的事務。如果方法已經運行在一個事務中,則原有事務會被掛起,新的事務會被創建,直到方法執行結束,新事務才算結束,原先的事務才會恢復執行。

你說說答案和上面是一樣的莫?😀

@Transactional(propagation = Propagation.REQUIRES_NEW) @Override public void purchase(int userId, int isbn) {// 獲取要買的圖書double bookPrice = bookShopMapper.getBookPriceByIsbn(isbn);// 更新圖書的庫存bookShopMapper.updateBootStock(isbn);// 更新用戶的余額bookShopMapper.updateAccountBalance(userId,bookPrice); }

答案是不一樣的,測試一 我們實際上用的就是checkout上的事務,并沒有用到 purchase 的事務,從圖上也能看出來。

測試二它的事務傳播屬性 用 圖來講是這樣的啦:

所以是可以買到一本書的。

還有很多,意思都解釋過了,沒有一一測完了。

三、數據庫事務隔離級別

3.1、數據庫事務并發問題

假設現在有A和B 兩個事務 并發執行。

1)臟讀:一個事務讀取到另一事務未提交的更新新據

  • A 將某條記錄的 age 值 從 20修改為30
  • B 讀取了 A 更新后的值為 30
  • A 回滾,age值回到20
  • B 讀取到的30 的值就是一個無效的值

2)不可重復讀: 同一事務中,多次讀取同一數據返回的結果有所不同(針對的update操作)

  • A 讀取了 age 值 為 20
  • B 將 age 值修改為30
  • A 再次讀去age 的值為30

3)幻讀:一個事務讀取到另一事務已提交的insert數據(針對的insert操作)

  • A 讀取 學生表 中一部分數據
  • B 向學生表中插入了 新的數據
  • A 讀取 學生表時 多出了一些行
  • 3.2 數據庫隔離性

    數據庫事務的隔離性: 數據庫系統必須具有隔離并發運行各個事務的能力, 使它們不會相互影響, 避免各種并發問題.

    一個事務與其他事務隔離的程度稱為隔離級別. 數據庫規定了多種事務隔離級別, 不同隔離級別對應不同的干擾程度, 隔離級別越高, 數據一致性就越好, 但并發性越弱

    在代碼中,我們可以通過

    數據庫提供了4種隔離級別:

    臟讀不可重復讀幻讀
    Read uncommitted (讀未提交)
    Read committed(讀已提交)
    Repeatable read (重復讀)
    Serializable(序列化)
    • Oracle 默認的事務隔離級別為: READ COMMITED ,Oracle 支持的 2 種事務隔離級別:READ COMMITED, SERIALIZABLE.
    • Mysql 默認的事務隔離級別為: REPEATABLE READ,Mysql 支持 4 種事務隔離級別.

    3.3、測試

    注: 模擬并發情況。

    1) 測試以下 mysql 的默認隔離級別:

    public interface BookShopService {void purchase(int userId,int isbn);// 測試事務隔離級別void transactionIsolationTest(int isbn); } /*** propagation :用來設置事務傳播屬性* Propagation.REQUIRED 默認事務傳播屬性** isolation :用來設置事務隔離級別* Isolation.REPEATABLE_READ: mysql 默認事務隔離* Isolation.READ_COMMITTED: oracle 默認事務隔離級別*/@Transactional(propagation = Propagation.REQUIRED,isolation = Isolation.REPEATABLE_READ)@Overridepublic void transactionIsolationTest( int isbn) {// 獲取要買的圖書 double bookPrice = bookShopMapper.getBookPriceByIsbn(isbn);//此處應打上斷點,待代碼執行完上一句后,應手動將書的價格修改一下,看讀到的數據是多少System.out.println(bookPrice);double bookPrice2 = bookShopMapper.getBookPriceByIsbn(isbn);System.out.println(bookPrice2);}

    測試代碼特別簡單,但因為我是手動模擬,得打斷點、debug啟動,

    @Autowired BookShopService bookShopService; @Test void transactionIsolationTest(){bookShopService.transactionIsolationTest(1001); }

    當執行完第一個double bookPrice = bookShopMapper.getBookPriceByIsbn(isbn)語句時,應該去mysql 修改一下書的價格,這樣看一下結果。

    這個時候再接著執行??摧敵鍪裁础?/p>

    最后的結果仍然是50、50。因為mysql的默認事務隔級別是可重復讀,意思在這同一個事務中,可以重復讀。

    注:因為這是直接修改數據庫,其操作行為并不可取,此處只是為了模擬。其結果有時也非一定準確。

    四、自言自語

    每天進步一點點,那么很快就可以進步很多。

    你好,我是博主寧在春,下篇文章再見。😁😛

    總結

    以上是生活随笔為你收集整理的你了解过Spring支持的常用数据库事务传播属性和隔离级别吗?来一起看看吧!!!的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。