Spring 事務系列 - 編程式事務

什麼是事務?

數據庫事務(簡稱:事務)是數據庫管理系統執行過程中的一個邏輯單位,由一個有限的數據庫操作序列構成。

事務應該具有4個屬性:原子性、一致性、隔離性、持久性,這四個屬性通常稱爲ACID特性。
* 原子性(Atomicity):事務作爲一個整體被執行,包含在其中的對數據庫的操作要麼全部被執行,要麼都不執行。
* 一致性(Consistency):事務應確保數據庫的狀態從一個一致狀態轉變爲另一個一致狀態。一致狀態的含義是數據庫中的數據應滿足完整性約束。
* 隔離性(Isolation):多個事務併發執行時,一個事務的執行不應影響其他事務的執行。
* 持久性(Durability):已被提交的事務對數據庫的修改應該永久保存在數據庫中。

事務的隔離級別

在數據庫操作中,爲了有效保證併發讀取數據的正確性,提出的事務隔離級別。我們的數據庫鎖,也是爲了構建這些隔離級別存在的。

隔離級別 髒讀(Dirty Read) 不可重複讀(NonRepeatable Read) 幻讀(Phantom Read)
讀未提交(Read uncommitted) 可能 可能 可能
讀已提交(Read committed) 不可能 可能 可能
可重複讀(Repeatable read) 不可能 不可能 可能
可串行化(Serializable ) 不可能 不可能 不可能

說明:
* 讀未提交(Read Uncommitted):允許髒讀,也就是可能讀取到其他會話中未提交事務修改的數據
* 讀已提交(Read Committed):只能讀取到已經提交的數據。Oracle等多數數據庫默認都是該級別 (不重複讀)
* 可重複讀(Repeated Read):可重複讀。在同一個事務內的查詢都是事務開始時刻一致的,InnoDB默認級別。在SQL標準中,該隔離級別消除了不可重複讀,但是還存在幻象讀
* 串行讀(Serializable):完全串行化的讀,每次讀都需要獲得表級共享鎖,讀寫相互都會阻塞

Read Uncommitted這種級別,數據庫一般都不會用,而且任何操作都不會加鎖,這裏就不討論了。MySQL默認的事務隔離級別爲可重複讀(Repeated Read)。

一、編程式事務

在 Spring 出現以前,編程式事務管理對開發者來說是唯一選擇。熟悉Java JDBC 的人都知道,我們需要在代碼中顯式調用Connection 的setAutoCommit()、commit()、rollback()等事務管理相關的方法,這就是編程式事務管理。

1、JDBC 的編程式事務管理

public void save(User user) throws SQLException{
    Connection conn = datasource.getConnection();
    conn.setAutoCommit(false);
    try {
        PreparedStatement ps = conn.prepareStatement("insert into user(name,age) value(?,?)");
        ps.setString(1,user.getName());
        ps.setInt(2,user.getAge());
        ps.execute();
        conn.commit();
    } catch (Exception e) {
        e.printStackTrace();
        conn.rollback();
    }finally{
        conn.close();
    }
}

2、Hibernate 的編程式事務管理

Hibernate 中需要顯式調用beginTransaction()、commit()、rollback()等事務管理相關的方法,如下:

public void save(User user){
    Session session = hibernateDao.openSession();
    Transaction tx = null;
    try {
        tx = session.beginTransaction();  
        session.save(user);  
        tx.commit();  
    } catch (Exception e) {
        if(tx!=null){
            tx.rollback();
        }
    }finally{
        session.close();
    }
}

3、MyBatis 的編程式事務管理

MyBatis中,我們可以通過org.apache.ibatis.session.SqlSession 的commit()、rollback() 等事務管理相關的方法,代碼如下:

    String resource = "org/mybatis/example/mybatis-config.xml";
    InputStream in = Resources.getResourceAsStream(resource);
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(in);

    SqlSession session = sqlSessionFactory.openSession(false); // 打開會話,事務開始  
    try {  
        IUserMapper mapper = session.getMapper(IUserMapper.class);  
        User user = new User(9, "Test transaction");  
        int affectedCount = mapper.updateUser(user); // 因後面的異常而未執行commit語句  
        User user = new User(10, "Test transaction continuously");  
        int affectedCount2 = mapper.updateUser(user2); // 因後面的異常而未執行commit語句  
        int i = 2 / 0; // 觸發運行時異常  
        session.commit(); // 提交會話,即事務提交  
    } catch (Exception e) {
        session.rollback(); //回滾
    } finally {  
        session.close(); // 關閉會話,釋放資源  
    }  

參考資料

分佈式事務系列(1.2)Spring的事務體系:https://yq.aliyun.com/articles/39046?spm=5176.100239.blogcont39044.27.mmXvhw

發佈了486 篇原創文章 · 獲贊 405 · 訪問量 296萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章