Spring六、Spring ORM


一、數據庫事務

1. 事務的基本概念

  事務(Transaction)是訪問並可能更新數據庫中各項數據項的一個執行單元(unit)。是恢復和並發控制的基本單位。
  事物的ACID4個特性:原子性、一致性、隔離性、持久性

  原子性(Automicity):一個事務是一個不可分割的工作單位,事務中的事情要么都做、要么都不做。
  一致性(Consistency):事務必須是使數據庫從一個一致性狀態到另一個一致性狀態,一致性與原子性是密切相關的。
  隔離性(Isolation):一個事務的執行不能被其它事務所干擾。即一個事物內所修改及使用得數據對其它並行的事務來說是隔離的,並發執行的各個單位不能互相干擾。
  持久性(Durability):持久性也成永久性,指一個事物一旦提交,它對數據庫的改變應該是永久性的。 

2. 數據庫隔離級別

  讀未提交、讀已提交、可重復讀、串行化。

隔離級別 隔離級別的值 導致的問題
Read-Uncommited 0 導致臟讀
Read-Committed 1 避免臟讀;允許不可重復讀、幻讀;
Repeatable-Read 2 避免臟讀、不可重復讀;允許幻讀;- 類似 行鎖
Serializable 3 串行化,一個事務執行完才能執行下一個,避免臟讀、不可重復讀、幻讀; 執行效率慢,使用時慎重;- 類似表鎖

  臟讀:事務可以讀取別的事務還未提交的數據。比如同一條數據,A事務先讀取到然后做了修改但事務並未提交,此時B事務去讀取數據會讀取到A事務修改后的數據,此時A事務回滾,B事務也就讀取到了臟數據。
  不可重復讀:針對單條數據。一個事物中發生了兩次讀操作,在第一次讀操作和第二次讀操作中,另一個事務對數據做了修改並提交了事務,則在第一個事務內兩次讀取到的數據時不同的。
  幻讀:針對多條數據。A事務執行批量更新操作,更新了一批數據;B事務在這個范圍內新增了一條數據,此時A事務並不會對這條數據做修改。
  數據庫隔離級別設置的越高,越能保證數據的完整性和一致性,但是對並發的性能影響也越大。
  大部分數據庫的隔離級別默認是讀已提交(Read-Commited),如SqlServer、Oracle。
  少數數據庫的默認隔離級別是可重復讀(Repeatable-Read),如Mysql、InnoDB

二、Spirng事務

1. Spring事物的基礎配置

  先來看下常用的Spring事物的基礎配置

	<aop:aspectj-autoproxy proxy-target-class="true"/>
	
	<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<property name="dataSource" ref="dataSource"/>
	</bean>

	<!-- 配置事務通知屬性 -->
	<tx:advice id="transactionAdvice" transaction-manager="transactionManager">
		<tx:attributes>
			<tx:method name="add*" propagation="REQUIRED" rollback-for="Exception,RuntimeException,SQLException"/>
			<tx:method name="remove*" propagation="REQUIRED" rollback-for="Exception,RuntimeException,SQLException"/>
			<tx:method name="edit*" propagation="REQUIRED" rollback-for="Exception,RuntimeException,SQLException"/>
			<tx:method name="login" propagation="NOT_SUPPORTED"/>
			<tx:method name="query*" read-only="true"/>
		</tx:attributes>
	</tx:advice>

	<aop:config>
	  <aop:advisor advice-ref="transactionAdvice" pointcut-ref="transactionPointcut"/>
          <aop:aspect ref="dataSource">
            <aop:pointcut id="transactionPointcut" expression="execution(public * com.gupaoedu..*.service..*Service.*(..))" />
          </aop:aspect>
        </aop:config>
	   

  Spring事物的管理基於Spring AOP實現,同一封裝非功能性需求。

2. Spring事物的基本原理

  Spring事物的本質其實是數據庫對事務的支持,沒有數據庫的事務支持,Spring是無法提供事務功能的。對於底層使用JDBC操作數據庫,用到事務的邏輯,可以參考下面的demo:

    public void testJdbc() {
        Connection conn = null;
        Statement stmt = null;

        try {
            // 注冊 JDBC 驅動
            // Class.forName("com.mysql.jdbc.Driver");

            // 1. 打開連接
            conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/mybatis", "root", "");

            // 2. 開啟手動提交事務
            conn.setAutoCommit(false);

            // 3. 執行CURD
            stmt = conn.createStatement();
            String sql = "update blog set name='測試' where bid = 1";
            int i = stmt.executeUpdate(sql);

            // 4.提交事務
            conn.commit();
            System.out.println(i);

        } catch (Exception e) {
            try {
                // 4.回滾事務
                conn.rollback();
            } catch (SQLException e1) {
                e1.printStackTrace();
            }
            e.printStackTrace();
        } finally {
            try {
                // 5.釋放資源
                if (stmt != null) stmt.close();
            } catch (SQLException se2) {
            }
            try {
                if (conn != null) conn.close();
            } catch (SQLException se) {
                se.printStackTrace();
            }
        }
    }

  Spring項目日常開發我們經常使用@Transactional注解來來進行事物管理,而不再需要我們寫步驟2和步驟4,那么Spring又是怎么實現的呢?
  首先在程序啟動時,Spring會根據我們配置的component-scan掃描包路徑,解析相關的bean,這時候會查看這個類以及方法上的注解,針對使用了@Transactional的類和方法會重新生成代理,並根據@Transactional的相關參數進行配置注入,在代理類中字節碼重組重新為原邏輯添加了開啟事務,正常執行提交事務、異常回滾事務的邏輯。真正的數據庫事務的提交和回滾則是由其內部機制,通過binlog或者redo log實現的。

3. Spring事務的傳播屬性

  在使用@Transactional注解時,默認傳播屬性為Propagation propagation() default Propagation.REQUIRED;

常量名稱 解釋
Propagation.REQUIRED 支持當前事務,如果當前沒有事務就新建一個事務。這種是Spring最常見的傳播屬性,也是Spring默認的事務傳播。
Propagation.REQUIRES_NEW 使用一個新的事務,如果當前沒有事務就新建一個事務,如果有事務則將當前事務掛起再新建事務。新的事物和原事務沒有任何關系,是兩個獨立的事務,外層事務出錯回滾之后不能回滾內層事務的結果,內層事務失敗回滾外層捕獲到也可以忽略回滾操作。
Propagation.SUPPORTS 支持當前事務,如果當前沒有事務則以非事務方式執行。
Propagation.MANDATORY 支持當前事務,如果當前沒有事務則拋出異常。必須在有外部事務的方法內執行。
Propagation.NOT_SUPPORTED 不支持事務,如果當前有事務則將當前事務掛起再執行
Propagation.NEVER 以非事務方式執行,如果當前存在事務則拋出異常。
Propagation.NESTED 如果沒有活動事務,則按REQUIRED方式執行。如果一個活動的事務存在,則運行在一個嵌套的事務中,內部事務是一個依賴於外部事務的子事務,此時外部事務擁有多個可以單獨回滾的保存點。內部事務的回滾不會對外部事務造成影響。內部事務不能單獨commit和rollback,會隨外部事務一起commit或rollback。

NESTED 事務嵌套
  NESTED和REQUIRES_NEW的卻別在於,如果外部方法存在事務,當內部方法是NESTED時,會先在外部事務產生一個savepoint,然后開啟一個子事務,子事務是依賴於外部事務的,外部事務commit子事務也隨之commit,外部事務rollback子事務也會rollback,子事務內發生異常,會先回滾到之前的savepoint,外部事務捕獲到子事務異常后可以根據真實需求來做后續處理;而REQUIRES_NEW在外部方法存在事務時,子方法會先將外部事務掛起,然后新建一個完全獨立的事務來執行,內部事務和外部事務互不影響。

4. Spring中的隔離級別

  在使用@Transactional注解時,默認隔離級別為Isolation isolation() default Isolation.DEFAULT;

    @Transactional(propagation = Propagation.REQUIRES_NEW, isolation = Isolation.READ_COMMITTED)
    public void updateLog(BatchPreviousEntity bpe) {
        ...
    }
常量名稱 解釋
Isolation.DEFAULT 是PlatformTransactionManager的默認隔離級別,使用數據庫默認的事務隔離級別。另外4個與數據庫的隔離級別相對應。
Isolation.READ_UNCOMMITTED 讀未提交
Isolation.READ_COMMITTED 讀已提交
Isolation.REPEATABLE_READ 可重復讀
Isolation.SERIALIZABLE 串行化


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM