事務是什麼?瞭解事務的原理嗎?說下Spring的事務原理,能自己實現Spring事務原理嗎?先自我檢測下這些知識掌握了嗎。那麼接下來一起看下與Spring相關的事務
概念
事務具有ACID特性。
是指作為單個邏輯工作單元執行的一系列操作,要麼完全地執行,要麼完全地不執行。
Spring事務的底層依賴MySQL的事務,程式碼層面上利用AOP實現。MySQL的事務有隔離級別的概念,只有InnoDB有事務,並且實現方式是利用undo log和redo log。
AOP方面,有連線點,切點,增強,目標,織入。參考Spring AOP入門,Spring則是在程式碼層面執行事務的時候使用TransactionInceptor進行攔截,然後處理。
系統解析Spring事務原理文章:
程式碼
- 在AopConfigUtils可以看到具體會生成什麼型別的AutoProxyCreator,這幾個都是beanPostProcessor,在Bean建立之後對Bean的例項進行自定義處理。如果使用了@EnableTransactionManagement,經過一些配置這次生成的是InfrastructureAdvisorAutoProxyCreator,具體如何生成這個類的點進去@EnableTransactionManagement裡面即可。
EnableTransactionManagement
-> @Import(TransactionManagementConfigurationSelector.class)
-> return new String[] {AutoProxyRegistrar.class.getName(),
ProxyTransactionManagementConfiguration.class.getName()};
-> AutoProxyRegistrar.registerBeanDefinitions中
-> 建立InfrastructureAdvisorAutoProxyCreator
複製程式碼
-
在Bean的生命週期中,Bean建立完成呼叫建立InfrastructureAdvisorAutoProxyCreator.postProcessAfterInitialization方法。
另外AbstractAutowireCapableBeanFactory.initializeBean方法也值得一看
獲取Bean的Advice,如果有Advice(增強的話),建立bean的動態代理。建立動態代理都是Spring AOP做的事情了,根據設定就是建立JDK動態代理和CGLib代理了,我們專案預設都是使用CGLib動態代理(proxyTargetClass=true即可),只說下CGlib的動態代理,主要利用了Enhancer類
這裡有Enhacer用法Cglib的使用方法(1)--Enhancer
攔截介面intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy)有我們根據條件進行是否要攔截的資料,根據引數就可以判斷。
-
可以跟進去DefaultAdvisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice方法中看
PointcutAdvisor為BeanFactoryTransactionAttributeSourceAdvisor MethodMatcher為TransactionAttributeSourcePointcut 複製程式碼
得到的攔截器為事務攔截器,既然是事務攔截器,那麼可以跟上之前的分析了。
- 我們接著看為什麼獲取的攔截器是MethodInterceptor。在MethodMatcher.match中有AdvisorAdapter
而Advice是advisor中的,advisor是BeanFactoryTransactionAttributeSourceAdvisor
- 一種在TransactionProxyFactoryBean中預設的TransactionIntercetor
- 在預設的@EnableTransactionManagement註解中,將BeanFactoryTransactionAttributeSourceAdvisor的advice設定為TransactionIntercetor,這一步的註解生效,我們第一步就已經講過了。
- 方法是如何匹配的,TransactionAttributeSourcePointcut中matches方法,呼叫TransactionAttributeSource屬性判斷是否有method的屬性
然後呼叫computeTransactionAttribute(method, targetClass),判斷是否有事務屬性
AbstractFallbackTransactionAttributeSource.computeTransactionAttribute
--> AnnotationTransactionAttributeSource.determineTransactionAttribute 獲取方法屬性
--> 獲取到TransactionAttribute,然後返回
複製程式碼
- 到現在我們基本上解釋了,Spring的事務攔截器是如何生效的,攔截器什麼時候設定的,事務方法是如何匹配的。
事務不生效
- private方法不會生效,JDK中必須是介面,介面中不可能有private方法,而私有方法子類無法方法,也不會生效
- CGLib代理的時候,final方法不會生效,拋NullPointException
- protect方法的話,預設是隻允許public方法。
最後一個就是在當前的bean中非事務方法呼叫事務方法為什麼不生效?
public int save(String name, int age) throws Exception {
insert(name, age);
return 1;
}
@Transactional
public void insert(String name, int age){
jdbcTemplate.update("insert into user(id,name,age)values(1,'"+name+"',"+age+")");
jdbcTemplate.update("insert into user(id,name,age)values(2,'"+name+"',"+age+")");
jdbcTemplate.update("insert into user(id,name,age)values(1,'"+name+"',"+age+")");
}
複製程式碼
答:
經過最終驗證,得出如下結論:
如果先呼叫的save方法,在進行方法攔截的時候,方法攔截器首先獲取當前動態代理的物件所代理的原始物件。
比如FirstApp生成的動態代理名稱為FirstApp$CGlibxxx,這個時候通過getTarget獲取的物件即為FirstApp的例項。
接下來如果判斷當前的方法比如save方法沒有Advice(增強),則直接呼叫原物件的方法,即這個時候呼叫的是FirstApp.save方法。而不是FirstApp$CGLibxxx的save方法。可以跟程式碼。
最後
Spring事務這塊,如果認真看我寫的文章,相信你會收穫不少