Spring事務管理詳解(傳播屬性、隔離級別)

(一)事務的概述

事務指作爲單個邏輯工作單元執行的一系列操作,要麼完全地執行,要麼完全地不執行。事務在數據庫的增刪改操作中最爲常見。事務具有ACID的特性,即原子性、一致性、隔離性、持久性。通過JDBC首先來了解一下事務的運行原理:

(二)JDBC中的事務

事務的操作主要由三大模塊,即事務的開啓、事務的提交和事務的回滾。

首先寫一段jdbc操作事務的代碼,這裏用到的數據庫名爲user,只有name和age兩個屬性:

1.創建連接工具類:

public class ConnectionUtil {
    public final static String DB_DRIVER="com.mysql.jdbc.Driver";
    public final static String DB_URL="jdbc:mysql://localhost:3306/transactiontest";
    public final static String DB_USER="root";
    public final static String DB_PWD="123456";
    public static Connection getConnection() throws ClassNotFoundException, SQLException {
        Connection conn=null;
        Class.forName(DB_DRIVER);
        conn= DriverManager.getConnection(DB_URL,DB_USER,DB_PWD);
        System.out.println("數據庫連接成功");
        return conn;
    }
}

2.JDBC操作數據庫:

public class TransactionTest1 {
    public static void main(String[] args) {
        Connection conn=null;
        try {
            conn=ConnectionUtil.getConnection();
            //1.開啓事務
            conn.setAutoCommit(false);
            insertTest1(conn);
            //2.提交事務
            conn.commit();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException e) {
            e.printStackTrace();
            try {
                //3.事務的回滾
                conn.rollback();
                System.out.println("rollback success");
            } catch (SQLException ex) {
                System.out.println("rollback failed");
            }
        }finally {
            try {
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
    private static void insertTest1(Connection conn) throws SQLException {
        PreparedStatement stat=conn.prepareStatement("insert into user(name) values (?)");
        stat.setString(1,"sdxb");
        stat.executeUpdate();
        System.out.println("insert success");
        stat.close();
    }
}

代碼第七行關閉自動提交表示事務的開啓位置,進行一系列操作後(增刪改查),事務提交。如果此時沒有報錯,事務提交成功,業務完成。如果此時出現報錯,就會進入事務的回滾,回到最初的狀態,維持事務的一致性。

(三)Spring中的事務

Spring實現事務的方式有兩種,編程式事務管理聲明式事務管理

編程式事務管理在Spring中有兩種實現方式:使用TransactionTemplate和直接使用PlatformTransactionManager。

聲明式事務管理的其中一個代表就是@Transactional 註解,隨着Spring更新中逐步拋棄了配置文件的使用,使用@Transactional註解管理事務成了很常用的方式。

@Transactional註解的使用很簡單,在需要添加事務的方法上增加@Transactional註解

@Transactional的參數如下所示

參數名稱

功能描述

readOnly

該屬性用於設置當前事務是否爲只讀事務,設置爲true表示只讀,false則表示可讀寫,默認值爲false。例如:@Transactional(readOnly=true)

rollbackFor

該屬性用於設置需要進行回滾的異常類數組,當方法中拋出指定異常數組中的異常時,則進行事務回滾。例如:

指定單一異常類:@Transactional(rollbackFor=RuntimeException.class)

指定多個異常類:@Transactional(rollbackFor={RuntimeException.class, Exception.class})

rollbackForClassName

該屬性用於設置需要進行回滾的異常類名稱數組,當方法中拋出指定異常名稱數組中的異常時,則進行事務回滾。例如:

指定單一異常類名稱:@Transactional(rollbackForClassName="RuntimeException")

指定多個異常類名稱:@Transactional(rollbackForClassName={"RuntimeException","Exception"})

noRollbackFor

該屬性用於設置不需要進行回滾的異常類數組,當方法中拋出指定異常數組中的異常時,不進行事務回滾。例如:

指定單一異常類:@Transactional(noRollbackFor=RuntimeException.class)

指定多個異常類:@Transactional(noRollbackFor={RuntimeException.class, Exception.class})

noRollbackForClassName

該屬性用於設置不需要進行回滾的異常類名稱數組,當方法中拋出指定異常名稱數組中的異常時,不進行事務回滾。例如:

指定單一異常類名稱:@Transactional(noRollbackForClassName="RuntimeException")

指定多個異常類名稱:

@Transactional(noRollbackForClassName={"RuntimeException","Exception"})

propagation

該屬性用於設置事務的傳播行爲,具體取值可參考表6-7。

例如:@Transactional(propagation=Propagation.NOT_SUPPORTED,readOnly=true)

isolation

該屬性用於設置底層數據庫的事務隔離級別,事務隔離級別用於處理多事務併發的情況,通常使用數據庫的默認隔離級別即可,基本不需要進行設置

timeout

該屬性用於設置事務的超時秒數,默認值爲-1表示永不超時

在@Transactional的參數中,尤其需要注意的是傳播屬性(propagation)和隔離級別(isolation):

(四)Spring事務的傳播屬性

事務的傳播屬性只在Spring中存在,在數據庫中的事務中不存在傳播屬性的說法

Spring的傳播屬性有以下七種:

PROPAGATION_REQUIRED--支持當前事務,如果當前沒有事務,就新建一個事務。(默認)

PROPAGATION_SUPPORTS--支持當前事務,如果當前沒有事務,就以非事務方式執行。

PROPAGATION_MANDATORY--支持當前事務,如果當前沒有事務,就拋出異常。

PROPAGATION_REQUIRES_NEW--新建事務,如果當前存在事務,把當前事務掛起。

PROPAGATION_NOT_SUPPORTED--以非事務方式執行操作,如果當前存在事務,就把當前事務掛起。

PROPAGATION_NEVER--以非事務方式執行,如果當前存在事務,則拋出異常。

PROPAGATION_NESTED--如果當前存在事務,則在嵌套事務內執行。如果當前沒有事務,則進行與PROPAGATION_REQUIRED類似的操作。

4.1 重要傳播屬性的解釋:

假設有ServiceA.MethodA(),在其內部調用ServiceB.MethodB()

PROPAGATION_REQUIRED

Spring默認使用PROPAGATION_REQUIRED傳播屬性,當ServiceA.MethodA()運行時,開啓一個事務,此時ServiceB.MethodB()方法發現已經存在一個事務,就不會再開啓事務,因此不管哪一個方法報錯,都會回調。

PROPAGATION_REQUIRES_NEW

新建事務,如果當前存在事務,把當前事務掛起。當ServiceA.MethodA()運行時,開啓一個事務A。當運行ServiceB.MethodB()時,把事務A掛起,然後開啓事務B。就算事務A發生回滾,事務B依然能正常提交。總結起來就是:外部事務不會影響內部事務的提交和回滾。

PROPAGATION_NESTED

如果當前存在事務,則在嵌套事務內執行。關於嵌套需要首先了解檢查點的概念:當在事務中設置檢查點後,如果發生回滾,會回滾到設置檢查點的位置,而不是回滾整個事務。嵌套事務就使用了檢查點Savepoint。當ServiceA.MethodA()運行時,開啓一個事務A。當運行ServiceB.MethodB()時,開啓一個子事務B,它將取得一個 savepoint. 如果這個事務B失敗, 將回滾到此 savepoint,而不會影響整個事務。總結一句話就是內部事務不會影響外部事務的提交和回滾

(五)Spring事務的隔離級別

首先了解一下三種數據庫中可能會發生的三種問題:

髒讀:一個事務讀到另一個事務未提交的更新數據

不可重複讀 : 前後多次讀取,數據內容不一致

幻讀: 前後多次讀取,數據總量不一致

Spring的隔離級別:

1.  ISOLATION_DEFAULT: 這是一個 PlatfromTransactionManager  默認的隔離級別,使用數據庫默認的事務隔離級別.

2.  ISOLATION_READ_UNCOMMITTED:讀未提交。這是事務最低的隔離級別,這種隔離級別會產生髒讀,不可重複讀和幻像讀。

3. ISOLATION_READ_COMMITTED讀已提交,ORACLE默認隔離級別,有幻讀以及不可重複讀風險。

4. ISOLATION_REPEATABLE_READ: 可重複讀,解決不可重複讀的隔離級別,但還是有幻讀風險。

5. ISOLATION_SERIALIZABLE  串行化,最高的事務隔離級別,不管多少事務,挨個運行完一個事務的所有子事務之後纔可以執行另外一個事務裏面的所有子事務,解決髒讀、不可重複讀和幻讀。

隔離級別並非越高越好,越高的隔離級別意味着越大的資源消耗,因此需要做適當取捨。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章