使用注解 + AOP代理的方式對業務包方法的標記,配置繼承AbstractRoutingDataSource類實現對於數據源的切換.
測試時, 可以進行查詢,但不能進行更新插入等寫數據庫操作。
使用@order() 默認值為2147483647,對切換數據源的注解和開啟事務注解進行標注, 測試失敗。
應用啟動時使用了@EnableTransactionManagement() 開啟了事務管理。
用AOP切換數據源,AOP的切點必須在事務開啟之前切換,否則無效,因為spring一旦使用事務獲取連接,
則會在事務開啟后獲取到連接,后面的都是放入當前線程中,即事務內所用的連接都是同一個,此時是無法改變的,
必須要在事務開啟前切換好數據源才能達到目的。
解決方法:編寫事務配置類,配置事務管理器PlatformTransactionManager,定義相關業務接口和實現類新的事務傳播行為。
(傳播行為定義了被調用方法的事務邊界) REQUIRES_NEW(),配置自定義的事務攔截器,將服務接口及實現類配置進去。
- PlatformTransactionManager
package org.springframework.transaction; import org.springframework.lang.Nullable; public interface PlatformTransactionManager { //事務狀態 TransactionStatus getTransaction(@Nullable TransactionDefinition var1) throws TransactionException; //提交事務 void commit(TransactionStatus var1) throws TransactionException; //回滾事務 void rollback(TransactionStatus var1) throws TransactionException; }
- 配置事務管理器
@Bean(CUSTOMIZE_TRANSACTION_INTERCEPTOR_NAME) public TransactionInterceptor customizeTransactionInterceptor(PlatformTransactionManager transactionManager) { NameMatchTransactionAttributeSource transactionAttributeSource = new NameMatchTransactionAttributeSource(); RuleBasedTransactionAttribute readOnly = this.readOnlyTransactionRule(); RuleBasedTransactionAttribute required = this.requiredTransactionRule(); // 默認的只讀事務配置
for (String methodName : DEFAULT_READ_ONLY_METHOD_RULE_TRANSACTION_ATTRIBUTES) { transactionAttributeSource.addTransactionalMethod(methodName, readOnly); } // 默認的傳播事務配置
for (String methodName : DEFAULT_REQUIRED_METHOD_RULE_TRANSACTION_ATTRIBUTES) { transactionAttributeSource.addTransactionalMethod(methodName, required); } // 定制的只讀事務配置
for (String methodName : customizeReadOnlyMethodRuleTransactionAttributes) { transactionAttributeSource.addTransactionalMethod(methodName, readOnly); } // 定制的傳播事務配置
for (String methodName : customizeRequiredMethodRuleTransactionAttributes) { transactionAttributeSource.addTransactionalMethod(methodName, required); } return new TransactionInterceptor(transactionManager, transactionAttributeSource); }
- 配置攔截器
@Bean public BeanNameAutoProxyCreator customizeTransactionBeanNameAutoProxyCreator() { BeanNameAutoProxyCreator beanNameAutoProxyCreator = new BeanNameAutoProxyCreator(); // 設置定制的事務攔截器
beanNameAutoProxyCreator.setInterceptorNames(CUSTOMIZE_TRANSACTION_INTERCEPTOR_NAME); // 默認
for ( String defaultTransactionBeanNameSuffix : DEFAULT_TRANSACTION_BEAN_NAMES ) { beanNameAutoProxyCreator.setBeanNames( defaultTransactionBeanNameSuffix ); } // 定制
for (String customizeTransactionBeanName : customizeTransactionBeanNames) { beanNameAutoProxyCreator.setBeanNames(customizeTransactionBeanName); } beanNameAutoProxyCreator.setProxyTargetClass(true); return beanNameAutoProxyCreator; }
- 傳播行為
( 傳播行為定義了被調用方法的事務邊界 )
傳播行為 propagation | 意義 |
PROPAGATION_REQUIRED | 方法必須運行在一個事務內,如果當前存在一個事務,那么該方法運行在這個事務中,否則,將創建一個新的事務。 |
REQUIRES_NEW | 創建一個新的事務,如果存在當前事務的話,暫停(掛起)當前事務 。 |
SUPPORTS | 支持當前事務,如果當前沒有事務,就以非事務方式執行。 |
NOT_SUPPORTED | 不執行當前事務;總是執行非事務。 |
MANDATORY | 支持當前事務;如果當前事務不存在則拋出一個異常。 |
NESTED | 如果當前存在事務的話,執行一個嵌套的事務,不存在創建新的。 |
NEVER | 不支持當前事務;如果存在當前事務則拋出一個異常 |