1. 程式人生 > >Spring 學習(二十五)——事務其他屬性(隔離級別、回滾、只讀和過期)

Spring 學習(二十五)——事務其他屬性(隔離級別、回滾、只讀和過期)

併發事務所導致的問題

當同一個應用程式或者不同應用程式中的多個事務在同一個資料集上併發執行時, 可能會出現許多意外的問題

併發事務所導致的問題可以分為下面三種類型:

髒讀: 對於兩個事物 T1, T2, T1  讀取了已經被 T2 更新但 還沒有被提交的欄位. 之後, T2 回滾, T1讀取的內容就是臨時且無效的.

不可重複讀:對於兩個事物 T1, T2, T1  讀取了一個欄位, 然後 T2 更新了該欄位. 之後, T1再次讀取同一個欄位, 值就不同了.

幻讀:對於兩個事物 T1, T2, T1  從一個表中讀取了一個欄位, 然後

T2 在該表中插入了一些新的行. 之後, 如果 T1 再次讀取同一個表, 就會多出幾行.

 

 

事務的隔離級別

從理論上來說, 事務應該彼此完全隔離, 以避免併發事務所導致的問題. 然而, 那樣會對效能產生極大的影響, 因為事務必須按順序執行.

在實際開發中, 為了提升效能, 事務會以較低的隔離級別執行.

事務的隔離級別可以通過隔離事務屬性指定

 

 

Spring 支援的事務隔離級別

事務的隔離級別要得到底層資料庫引擎的支援, 而不是應用程式或者框架的支援.

Oracle 支援的 2 種事務隔離級別:

READ_COMMITED , SERIALIZABLE

Mysql 支援 4 中事務隔離級別.

 

 

設定隔離事務屬性

@Transactional 註解宣告式地管理事務時可以在 @Transactional isolation 屬性中設定隔離級別.

Spring 2.x 事務通知中, 可以在 <tx:method> 元素中指定隔離級別

 

設定回滾事務屬性

預設情況下只有未檢查異常(RuntimeExceptionError型別的異常)會導致事務回滾. 而受檢查異常不會

.

事務的回滾規則可以通過 @Transactional 註解的 rollbackFor noRollbackFor 屬性來定義. 這兩個屬性被宣告為 Class[] 型別的, 因此可以為這兩個屬性指定多個異常類.

rollbackFor遇到時必須進行回滾

noRollbackFor: 一組異常類,遇到時必須不回滾

 

 

設定回滾事務屬性

Spring 2.x 事務通知中, 可以在 <tx:method> 元素中指定回滾規則. 如果有不止一種異常, 用逗號分隔.

 

超時和只讀屬性

由於事務可以在行和表上獲得鎖因此長事務會佔用資源, 並對整體效能產生影響.

如果一個事物只讀取資料但不做修改, 資料庫引擎可以對這個事務進行優化.

超時事務屬性: 事務在強制回滾之前可以保持多久. 這樣可以防止長期執行的事務佔用資源.

只讀事務屬性: 表示這個事務只讀取資料但不更新資料, 這樣可以幫助資料庫引擎優化事務.

 

 

設定超時和只讀事務屬性

超時和只讀屬性可以在 @Transactional 註解中定義.超時屬性以秒為單位來計算.

Spring 2.x 事務通知中, 超時和只讀屬性可以在 <tx:method> 元素中進行指定.

 

 

程式碼示例:

其他程式碼在上篇部落格

package com.hzyc.spring.jdbc.transaction;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

/**
 * @author xuehj2016
 * @Title: BookShopServiceImpl
 * @ProjectName Spring-3
 * @Description: TODO
 * @date 2018/12/21 21:24
 */
@Service("bookShopService")
public class BookShopServiceImpl implements BookShopService {

    @Autowired
    private BookShopDao bookShopDao;

    /**
     * 新增事務註解
     * 1.使用 propagation 指定事務的傳播行為, 即當前的事務方法被另外一個事務方法呼叫時
     * 如何使用事務, 預設取值為 REQUIRED, 即使用呼叫方法的事務
     * REQUIRES_NEW: 事務自己的事務, 呼叫的事務方法的事務被掛起.
     * 2.使用 isolation 指定事務的隔離級別, 最常用的取值為 READ_COMMITTED
     * 3.預設情況下 Spring 的宣告式事務對所有的執行時異常進行回滾. 也可以通過對應的
     * 屬性進行設定. 通常情況下去預設值即可.
     * Transactional(propagation=Propagation.REQUIRES_NEW,
     * isolation=Isolation.READ_COMMITTED,
     * noRollbackFor={UserAccountException.class})
     * 4.使用 readOnly 指定事務是否為只讀. 表示這個事務只讀取資料但不更新資料,
     * 這樣可以幫助資料庫引擎優化事務. 若真的事一個只讀取資料庫值的方法, 應設定 readOnly=true
     * 5.使用 timeout 指定強制回滾之前事務可以佔用的時間.單位為 s
     * Thread.sleep(5000) 單位為 ms
     *
     * @param username
     * @param id
     */
    @Transactional(propagation = Propagation.REQUIRES_NEW,
            isolation = Isolation.READ_COMMITTED,
            readOnly = false,
            timeout = 3)
    @Override
    public void purchase(String username, String id) {

        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        //1.獲取書的單價
        int price = bookShopDao.getBookPriceById(id);

        //2.更新書的庫存
        bookShopDao.updateBookStock(id);

        //3.更新使用者餘額
        bookShopDao.updateUserAccount(username, price);
    }
}