spring本身對AOP的運用 -- spring事物(transaction)原理

aop即Aspect-Oriented Programming ,面向切面編程。html

  • Aspect:切面。在代碼的執行過程當中,老是有一些邏輯在多個模塊中是同樣的,這個時候,這些多個處理邏輯同樣的地方就能夠放在一個地方處理。這種處理就感受像是在代碼的各個模塊文件中,橫向切開了一刀,插入額一段新的邏輯,這些新邏輯的代碼文件像是橫叉在全部代碼的一個切面,通過這個平面處理以後再回到原有的執行邏輯
  • Join Point:公共程序執行的位置,對於spring來講,表示方法的執行(要支持字段的更新能夠選擇AspectJ)
  • Point cut:適配全部Join Point的表達式,用來篩選是和執行公共代碼的方法
  • Advice:切面中實際執行的代碼,它能夠在方法執行前、執行後、扔出異常等等的位置
  • Target Object:切面執行完後,原始程序須要執行的內容,對於切面來講,這個就是須要它代理要執行的對象
  • Advisor:代碼實現,負責組織好 Advice/Point cut/要代理的對象 的關係

spring 4.2.x 文檔介紹java

Aop代碼中運用

可使用xml或者註解的方式在項目中使用aop,以註解爲例,通常使用能夠引用 AspectJ,本身建立一個類,在類上標註好註解 @Aspectgit

@Aspect
public class LogAspect {}
複製代碼

在xml中開啓掃描便可找到這個註解github

<aop:aspectj-autoproxy />
複製代碼

在代碼中創建好對應的Point Cutspring

@Pointcut("execution(* paxi.maokitty.verify.spring.aop.service.ExecuteService.*(..))")
    public void allClassPointCut(){}
複製代碼

這裏PointCut表達式指定類paxi.maokitty.verify.spring.aop.service.ExecuteService全部方法都是目標對象數據庫

創建本身須要執行的方法(advice)編程

@Before("allClassPointCut()")
    public void beforeAspectExecuteService(JoinPoint joinPoint){
        LOG.info("beforeAspectExecuteService execute method:{}",new Object[]{joinPoint.getStaticPart().toShortString()});
    }
複製代碼

便可達到對應的目標,並且這種方式作到了對原有代碼的無入侵,體驗很好。完整的可運行實例請戳這裏bash

經過代碼的方式組織aop能夠戳這裏併發

spring中的事務對aop的使用

事務

此處不討論分佈式事務分佈式

事務是數據庫執行過程當中的一個邏輯單位,由一個有限的數據庫操做序列構成。當事務被提交給了數據庫,數據庫須要確保該事務中的全部操做都成功完成而且結果被永遠保存在數據庫中。若是事務中有的操做沒有成功的完成,則事務中的全部操做都須要回滾,回到事務執行前的狀態,同時,該事務對數據庫的其餘事務執行沒有影響。數據庫事務通常擁有如下四個特性

  • 原子性:事務中全部的操做要麼都成功要麼都失敗
  • 一致性:確保數據庫從一個一致狀態轉變成另外一個一致的狀態
  • 隔離性:多個事務併發執行不會互相影響
  • 持久性:已被提交的事務對數據庫的修改應該永遠的保存在數據庫中

數據庫事務描述-維基百科

java對事務的代碼實現

java中操做數據庫操做的關鍵類是 Connection ,它表明了對數據庫的一個鏈接,經過對應的方法

  • connection.commit():執行事務的提交語義
  • con.rollback();:執行事務的回滾語義 能夠控制事務操做

事務demo實例戳這裏
java事務處理全解析 - 無知者雲

spring中運用事務

spring中最簡單的實現只須要直接在要使用事務的類上添加註解 @Transactional,並在xml中添加註解的掃描<tx:annotation-driven transaction-manager="txManagerTest"/>基本就能夠利用spring的事務了

spring事務使用戳我

spring對事務的實現則是經過aop來實現的。spring在掃描tx標籤的時候,碰到transactional標註的類或者方法,會建立對應的AOP代理,在調用的時候則是AOP代理去執行,先按照AOP的方式執行相應的邏輯,再執行用戶定義的方法,若是有問題則執行對應的事務

@Trace(
            index = 13,
            originClassName = "org.springframework.transaction.interceptor.TransactionAspectSupport",
            function = "protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass,final InvocationCallback invocation) throws Throwable"
    )
    public void  invokeWithinTransaction(){
        //...
        Code.SLICE.source("final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);")
                .interpretation("查到對應方法的事務配置");
        Code.SLICE.source("final PlatformTransactionManager tm = determineTransactionManager(txAttr);")
                .interpretation("拿到transactionManager,好比用戶在xml中配置的 org.springframework.jdbc.datasource.DataSourceTransactionManager");
        Code.SLICE.source("final String joinpointIdentification = methodIdentification(method, targetClass);")
                .interpretation("獲取transaction標註的方法");
        //...
        Code.SLICE.source("TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);\n" +
                " Object retVal = null;\n" +
                " try {\n" +
                " retVal = invocation.proceedWithInvocation();\n" +
                " }\n" +
                " catch (Throwable ex) {\n" +
                " // target invocation exception\n" +
                " completeTransactionAfterThrowing(txInfo, ex);\n" +
                " throw ex;\n" +
                " }\n" +
                " finally {\n" +
                " cleanupTransactionInfo(txInfo);\n" +
                " }\n" +
                " commitTransactionAfterReturning(txInfo);\n" +
                " return retVal;")
                .interpretation("這裏就是標準的事務處理流程 1:獲取事務;2:執行用戶本身的方法;3:若是執行過程當中拋出了異常執行異常拋出後的事務處理邏輯 4:清除事務信息 5:提交事務");
        //...
    }

複製代碼

spring掃描tx註解到執行事務代碼追蹤詳情戳這裏

spring 事務具體執行邏輯

spring自定義了事務的傳播邏輯

  • PROPAGATION_REQUIRED :若是沒有事務就新建一個,有的話就在那個事務裏面執行。默認配置
  • PROPAGATION_SUPPORTS:沒有事務就什麼都不作,有事務則在當前事務中執行
  • PROPAGATION_MANDATORY:若是沒有事務就拋出異常
  • PROPAGATION_REQUIRES_NEW:建立新的事務,若是已經存在一個事務,就先把這個事務暫停,執行完新建的事務以後再恢復
  • PROPAGATION_NOT_SUPPORTED:方法不會在事務中執行,若是存在事務,會在方法執行期間被掛起
  • PROPAGATION_NEVER:若是有事務就拋出異常
  • PROPAGATION_NESTED:若是已經有一個事務,就再嵌套一個執行,被嵌套的事務能夠獨立於封裝事務進行提交或者回滾,若是不存在事務,則新建事務

這裏就注意到 所謂 物理事務 和 邏輯事務的區別

  • 物理事務就是底層數據庫提供的事務支持
  • 邏輯事務則是spring本身管理的事務,它與物理事務最大的區別就在於事務的傳播行爲,即多個事務在方法間調用時,事務是如何傳播的

spring對事務的隔離機制

  • TRANSACTION_READ_UNCOMMITTED :在一個事務中一行數據的改變,再實際提交以前,會被另外一個事務讀到,也就是說若是改變數據的事務發生回滾,那麼其它線程讀到的數據就是無效的
  • TRANSACTION_READ_COMMITTED:事務一行數據的改變,只有在數據提交以後才能讀到
  • TRANSACTION_REPEATABLE_READ: 事務一行數據的改變,只有在數據提交以後才能讀到。兩個事務,一個事務讀到一行數據,另外一個事務立馬進行了修改,若是第一個事務對數據再次進行讀取,此時它讀到的數據還和以前同樣
  • TRANSACTION_SERIALIZABLE:一個事務讀取到知足where條件的數據以後,另外一個事務同時插入了一行知足這個條件的數據,第一個事務再次讀取並不會讀到這個新的數據

事務的隔離機制與傳播機制源碼註解解釋各自含義,實際就是Connection的定義

對不一樣的隔離機制,也就產生了 髒讀、不可重複讀、幻讀的場景

Y表示會存在,N表示不存在

實質上就是在不一樣隔離機制下,多個事務讀取數據的影響

spring的具體源碼實現

spring自定義的傳播機制,實際上就是代碼的處理邏輯,在不一樣的場景下作出的限制

if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NEVER) {
	throw new IllegalTransactionStateException(
		"Existing transaction found for transaction marked with propagation 'never'");
	}
複製代碼

它底層去提交事務或是回滾事務,本質上仍是java的Connection來最終執行操做,另外對於對於一次訪問的多個數據庫的事務操做,spring本身將鏈接與線程創建了關聯關係,即每一個線程都持有的是同一個鏈接,來保證指望相同的數據庫操做在同一個事務裏面。源碼的詳細追蹤實例能夠戳這裏

個人博客即將同步至騰訊雲+社區,邀請你們一同入駐:cloud.tencent.com/developer/s…

相關文章
相關標籤/搜索