aop即Aspect-Oriented Programming ,面向切面編程。html
可使用xml或者註解的方式在項目中使用aop,以註解爲例,通常使用能夠引用 AspectJ,本身建立一個類,在類上標註好註解 @Aspect
git
@Aspect
public class LogAspect {}
複製代碼
在xml中開啓掃描便可找到這個註解github
<aop:aspectj-autoproxy />
複製代碼
在代碼中創建好對應的Point Cut
spring
@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
此處不討論分佈式事務分佈式
事務是數據庫執行過程當中的一個邏輯單位,由一個有限的數據庫操做序列構成。當事務被提交給了數據庫,數據庫須要確保該事務中的全部操做都成功完成而且結果被永遠保存在數據庫中。若是事務中有的操做沒有成功的完成,則事務中的全部操做都須要回滾,回到事務執行前的狀態,同時,該事務對數據庫的其餘事務執行沒有影響。數據庫事務通常擁有如下四個特性
java中操做數據庫操做的關鍵類是 Connection
,它表明了對數據庫的一個鏈接,經過對應的方法
connection.commit()
:執行事務的提交語義con.rollback();
:執行事務的回滾語義 能夠控制事務操做spring中最簡單的實現只須要直接在要使用事務的類上添加註解 @Transactional
,並在xml中添加註解的掃描<tx:annotation-driven transaction-manager="txManagerTest"/>
基本就能夠利用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本身管理的事務,它與物理事務最大的區別就在於事務的傳播行爲,即多個事務在方法間調用時,事務是如何傳播的
事務的隔離機制與傳播機制源碼註解解釋各自含義,實際就是Connection的定義
對不一樣的隔離機制,也就產生了 髒讀、不可重複讀、幻讀的場景
Y表示會存在,N表示不存在
實質上就是在不一樣隔離機制下,多個事務讀取數據的影響
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…