最新公司在按產品線拆分數據庫作Mysql多活,致使一個工程中有多個數據源,咱們產品線是最早拆出來的因此這些數據源,事務管理器的配置都是默認的,正常使用,可是在其餘產品線加入新的數據源及事務管理器後發現事務失效了,懷疑和配置方式有關。spring
com
後邊通常來講是公司名稱了呀。
上圖的1是後來的,後來者居上嘛,
pxhTransactionManager
是沒有問題的,由於好名字transactionManager
已經被咱們佔了嘛(首發除了探坑仍是有好處的),問題應該就出在了又定義了一次<tx:annotation-driven>
標籤。sql
這裏邊挺奇怪的,通常你們在工程中就直接是
<tx:annotation-driven/>
聲明下這個註解就好了,爲啥還要寫transaction-manager
屬性呢,這裏咱們推測(其實就是這樣)這是指定事務的默認的管理器,既然是默認那就有個默認的名字,沒錯如你們所想默認的名字就是transactionManager
,其實IDEA
已經給咱們提示了,以下圖數據庫
無用的聲明默認屬性,並且鼠標放上去
Alt+Enter
第一個提示是能夠刪除的app
定義屢次
tx
標籤就是很奇怪的事情,這能夠在單例天下的Spring
中,並且咱們根據結果和代碼能夠猜想,<tx:annotation-driven>
標籤採起的是先入爲主
的策略,致使咱們默認調用的事務管理器變成了pxhTransactionManager
,然而這並非咱們代碼須要調用的數據源,因此回滾無效spa
猜想必需要以代碼爲依據,既然標籤是定義在
XML
文件中的,那麼咱們就從Spring
解析咱們的配置文件開始看起,咱們從Spring
在Web.xml
文件中定義的啓動窗口開始,就是你們都知道的ContextLoaderListener
3d
Listener
均是ServletContextListener
的實現類在容器啓動的時候自行執行contextInitialized
方法,進入contextLoader.initWebApplicationContext
方法代理
這個方法主要是初始化容器上下文,具體的
bean
加載等方法在configureAndRefreshWebApplicationContext()
方法中code
進入
wac.refresh()
方法,這裏的wac
是類是XmlWebApplicationContext
,上邊的就不說了,太煩了沒看懂……cdn
XmlWebApplicationContext
這個類的繼承很複雜,這裏的refresh()
實際的代碼在AbstractApplicationContext
類中xml
直奔主題進入
obtainFreshBeanFactory()
方法
loadBeanDefinitions(beanFactory)
方法解析XML
文件,進入AbstractXmlApplicationContext
類中的loadBeanDefinitions()
方法中
進入
XmlWebApplicationContext.loadBeanDefinitions()
方法
進入
AbstractBeanDefinitionReader.loadBeanDefinitions()
的一系列重載方法,而後進入AbstractBeanDefinitionReader
類的loadBeanDefinitions(String location, Set<Resource> actualResources)
方法
進入
XmlBeanDefinitionReader
類的loadBeanDefinitions(EncodedResource encodedResource)
方法
通過
XmlBeanDefinitionReader
類的doLoadBeanDefinitions()
方法進入registerBeanDefinitions()
方法,
進入
DefaultBeanDefinitionDocumentReader
類的registerBeanDefinitions(Document doc, XmlReaderContext readerContext)
方法
而後進入
parseBeanDefinitions()
方法
像tx:這樣的標籤屬於自定義標籤走
BeanDefinitionParserDelegate.parseCustomElement()
方法
重點在於經過命名空間找到對應的處理類,進入
DefaultNamespaceHandlerResolver
類的resolve()
方法
下邊是
handlerMappings
命名空間和處理類的對應關係![]()
進入
TxNamespaceHandler
類,能夠看出來初始化了幾個關鍵的類
回到剛纔的入口,進入
NamespaceHandlerSupport.parse()
方法
能夠看出來須要執行
AnnotationDrivenBeanDefinitionParser.parse()
方法
能夠發現咱們熟悉的包都有身影出現,這裏咱們猜也是工廠模式的一種了,這裏其實就是各類須要引入命名空間的標籤的處理類了。咱們須要進入的是
spring-tx
包,在AnnotationDrivenBeanDefinitionParser
的內部靜態類AopAutoProxyConfigurer
的靜態方法configureAutoProxyCreator
是關鍵,這邊也解釋了爲何先入爲主,
只有當不存在這個類型的
bean
的時候,纔會對bean
初始化而且註冊到容器中,而xml
解析是從上到下的,因此咱們被放在下邊的事務管理器並不會起到應有的做用,而是被無情的拋棄。
一樣在這部分的代碼解釋了
transaction-manager
標籤屬性的解析過程,默認值也是在此設置的
在
TransactionInterceptor
類的invoke()
方法是事務代理對象的具體執行者,具體的代碼在TransactionAspectSupport.invokeWithinTransaction()
類,![]()
上圖的
completeTransactionAfterThrowing
方法,決定了在什麼異常發生時回滾,若是@Transactional
註解沒有指定rollbackFor
屬性的話,就進入DefaultTransactionAttribute
,s因此只會在RuntimeException
類型異常和Error
時回滾
其實解決方案網上都有,就是在@Transactional
註解裏邊指定對應的事務管理器,例如 @Transactional("pxhTransactionManager")
@Transactional("transactionManager")
具體緣由看下邊的代碼就知道了在
TransactionAspectSupport
類中