五.Spring之聲明式事務原理

需要了解@Import註解的應用https://blog.csdn.net/u014203449/article/details/86559350

後置處理器https://blog.csdn.net/u014203449/article/details/86665963

代理模式和方法攔截器https://blog.csdn.net/u014203449/article/details/105707730

 

一.演示案例

 環境搭建:
  1、導入相關依賴
          數據源、數據庫驅動、Spring-jdbc模塊
  2、配置數據源、JdbcTemplate(Spring提供的簡化數據庫操作的工具)操作數據
  3、給方法上標註 @Transactional 表示當前方法是一個事務方法;
  4、 @EnableTransactionManagement 開啓基於註解的事務管理功能;
          @EnableXXX
  5、配置事務管理器來控制事務;
          @Bean
          public PlatformTransactionManager transactionManager()

@EnableTransactionManagement
@ComponentScan("com.atguigu.tx")
@Configuration
public class TxConfig {
	
	//數據源
	@Bean
	public DataSource dataSource() throws Exception{
		ComboPooledDataSource dataSource = new ComboPooledDataSource();
		dataSource.setUser("wisdomclass");
		dataSource.setPassword("susOn@20190916");
		dataSource.setDriverClass("com.mysql.jdbc.Driver");
		dataSource.setJdbcUrl("jdbc:mysql://xxxx:3306/intelligent_admin");
		return dataSource;
	}
	
	//
	@Bean
	public JdbcTemplate jdbcTemplate() throws Exception{
		//Spring對@Configuration類會特殊處理;給容器中加組件的方法,多次調用都只是從容器中找組件
		JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource());
		return jdbcTemplate;
	}
	
	//註冊事務管理器在容器中
	@Bean
	public PlatformTransactionManager transactionManager() throws Exception{
		return new DataSourceTransactionManager(dataSource());
	}
	

}

service,發生一次異常

@Service
public class UserService {
	
	@Autowired
	private UserDao userDao;
	
	@Transactional
	public void insertUser(){
		userDao.insert();
		//otherDao.other();xxx
		System.out.println("插入完成...");
		int i = 10/0;
	}

}

dao ,保存一條數據

@Repository
public class UserDao {
	
	@Autowired
	private JdbcTemplate jdbcTemplate;
	public void insert(){
		String sql = "INSERT INTO `user_info`(`name`,sex) VALUES(?,?)";
		String username = UUID.randomUUID().toString().substring(0, 5);
		jdbcTemplate.update(sql, username,1);
		
	}

}

單元測試

	@Test
	public void test01(){
		AnnotationConfigApplicationContext applicationContext = 
				new AnnotationConfigApplicationContext(TxConfig.class);
	
		UserService userService = applicationContext.getBean(UserService.class);
		
		userService.insertUser();
		applicationContext.close();
	}

結果sql執行新增過後, 數據庫數據沒有變化,因爲異常導致事務回滾。

 

二.@EnableTransactionManagement

和AOP 的@Enable註解一樣,看看它給容器注入了什麼?

TransactionManagementConfigurationSelector,實現了ImportSelector接口,就看 selectImports方法的返回結果是什麼,就會往容器中注入什麼組件。

根據adviceMode的值去注入不同的組件。

adviceMode的值在 EnableTransactionManagement 中 默認爲 AdviceMode.PROXY,所以會注入 AutoProxyRegistrar 和ProxyTransactionManagementConfiguration。

proxyTargetClass ,默認值爲false,一會用到。

1.AutoProxyRegistrar

實現了 ImportBeanDefinitionRegistrar接口,可以用 BeanDefinitionRegistry 自定義往容器中註冊組件。

可以打斷點看看:

1.importingClassMetadata.getAnnotationTypes(); 得到一些標註的註解,並遍歷

2.AnnotationAttributes candidate = AnnotationConfigUtils.attributesFor(importingClassMetadata, annoType);得到註解的屬性

3.如果註解的mode屬性值不爲空,且屬性proxyTargetClass不爲空,且...符合後面的條件,最終會執行AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);

而proxyTargetClass ,默認值爲false,forceAutoProxy不會執行。

 會往容器中注入InfrastructureAdvisorAutoProxyCreator 實例

InfrastructureAdvisorAutoProxyCreator看繼承關係,和AOP的AnnotationAwareAspectJAutoProxyCreator很像,是個BeanPostProcessor。

沒有找到InfrastructureAdvisorAutoProxyCreator重寫postProcessAfterInitialization等後置處理的方法,說明它的功能和AbstractAutoProxyCreator一樣,如下和AOP一樣。

打斷點,查看userService的初始化(事務註解寫在了userService上),

會發現它有個增強器,最終會返回userService的代理對象。

跟AOP一樣,利用代理、增強器對原方法加強。

2.ProxyTransactionManagementConfiguration

給容器注入BeanFactoryTransactionAttributeSourceAdvisor,TransactionAttributeSource(解析事務註解的屬性),

TransactionInterceptor(方法攔截器)


 

TransactionInterceptor實現了MethodInterceptor,是個方法攔截器,在給userservice創建代理後,調用userService的方法時,會先執行它的invoke方法。

在單元測試調用userService保存時,打斷點,看看流程。

進入斷點,和AOP一樣,進入了CglibAopProxy的intercept方法。

得到方法連接器鏈chain中有一個元素,就是TransactionInterceptor

最後構造 CglibMethodInvocation 執行proceed方法。

執行proceed方法,斷點進入ReflectiveMethodInvocation的proceed

再進入斷點,就來到了TransactionInterceptor 的invoke

invokeWithinTransaction方法:根據方法名來看看

1)、先獲取事務相關的屬性 getTransactionAttribute


  2)、再獲取PlatformTransactionManager,如果事先沒有添加指定任何transactionmanger,最終會從容器中按照類型獲取一個PlatformTransactionManager;
3)、事務執行

    創建事務(createTransactionIfNecessary)

              --->執行目標方法(invocation.proceedWithInvocation())

                  ----->如果異常,獲取到事務管理器,利用事務管理回滾操作(completeTransactionAfterThrowing(txInfo, ex));
                  ----->如果正常,利用事務管理器,提交事務(commitTransactionAfterReturning(txInfo))


 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章