spring源碼分析——事務的實現原理


 

 

  在對數據庫進行操作時,有時候會把多個操作放到一個事務里,保證原子性,那么這個事務是怎么實現的呢?

下面我們先通過一個demo看一下事務的使用:

一:事務的使用

數據庫jdbc配置:

##數據源配置
jdbc.driverClass=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://127.0.0.1:3306/study
jdbc.username=root
jdbc.password=root

 

spring-context.xml配置:

	<!--加載properties配置文件-->
	<context:property-placeholder location="classpath*:*.properties" />

	<!-- 配置數據源 -->
	<bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource"
		  destroy-method="close">
		<property name="driverClassName" value="${jdbc.driverClass}" />
		<property name="url" value="${jdbc.url}" />
		<property name="username" value="${jdbc.username}" />
		<property name="password" value="${jdbc.password}" />
	</bean>

	<!-- 指定數據源和配置文件路徑 -->
	<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
		<property name="dataSource" ref="dataSource" />
		<!-- 自動掃描mapping.xml文件 -->
		<property name="mapperLocations" value="classpath:UserMapper.xml"></property>
	</bean>

	<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
		<property name="basePackage" value="com.hello.mapper"></property>
	</bean>

	<!-- 配置事務管理器 -->
	<bean id="transactionManager"
		  class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<property name="dataSource" ref="dataSource"/>
	</bean>

	<tx:annotation-driven/>

  

寫一個類,方法上加上@Transactional注解

@Service
public class TestTransactionalService {

    @Autowired
    private UserMapper userMapper;

    @Transactional
    public int add(){
        User user = new User();
        user.setName("Lucy");
        user.setAge("30");
        int effectCount = userMapper.insert(user);
		System.out.println("影響條數: "+effectCount);
		int i = 10/0;
		return effectCount;
    }

}

  

測試代碼:

 

 

 運行結果: 從結果可以看到影響條數為1,但是數據庫沒有數據,可以看出事務回滾生效了

 

 二:事務的原理分析

1:注冊埋點,注冊BeanDefinition對象,實例化BeanPostProcessor對象,並注冊到beanPostProcessors中

配置開啟事務管理:

 

通過命名空間找到對象的handler類:

 

 

 

 

注冊自定義標簽tx的屬性解析器,AnnotationDrivenBeanDefinitionParser

 

 

 

 

 

 

 

 

 

 

 

 

 

 AutoProxyCreator已經以BeanDefinition的形式注冊到了BeanDefinitionMaps中。

 

注冊其他類:

 

 

 

 

 

 

 

 

 

2:實例化並注冊到beanPostProcessors中

是在refresh方法的registryBeanPostProcessor中實現的,這里不再贅述

 

3:尋找增強,創建代理

 

 

 

 

 

 

 

 

 

 

 

 

 

 

用增強去匹配當前bean信息:

 

 

 

 

 

 

 

 

 

 

 

 

創建代理:

 

4:攔截方法,對方法進行增強

 

 TestTransactionalService這個對象已經被代理

 

進入DynamicAdvisedInterceptor類的intercept方法:

 

 

只有一個增強:

 

 

TransactionInterceptor 的 invoke方法

 

 

 

 

拋出異常,進入catch代碼塊:

 

 

回滾事務:

 

 

 

 

 

 DataSourceTransactionManager類的doRollback回滾方法:

 

 

可以看出正在執行回滾操作是在DataSourceTransactionManager類中進行的

 

 

下面把導致異常的代碼去掉,看一下提交的情況:

 

 

提交事務:

 

 

 

 

 

 

 

調到了DataSourceTransactionManager的doCommit事務:

 

 

到這里事務管理的分析就結束了,實現原理就是對數據庫的操作方法進行增強,如果執行成功就commit,執行失敗就rollback。

 

a: 看一下異常回滾里面小細節:rollbackFor ,什么異常才回滾?

 

 

 如果@Transactional注解上不配置rollbackFor 默認是RuntimException 或者 Error

 

 

 

如果自定義rollbackFor類型:

 

b:如果@Transactional注釋的方法不是public修飾的,也不會被代理,找不到@Transactional注解的信息

 

 

 

 

c:如果是內部調用,會不會生效,從其他類調用add方法:

 

 

調用add方法,進入intercept

 

 

 

   

在add方法中調用addData,實際是調用target的方法,不是代理方法,所以不會有事務的存在

 

 

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM