目录

一、环境准备

1、JdbcTemplate使用实例

2、事务添加

二、声明式事务源码分析

1、原理(与AOP非常相似)


一、环境准备

1、JdbcTemplate使用实例

(1)pom文件添加依赖

<!--c3p0数据源-->
<dependency><groupId>c3p0</groupId><artifactId>c3p0</artifactId><version>0.9.1.1</version>
</dependency>
<!--mysql驱动-->
<dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.44</version>
</dependency>
<!--jdbc-->
<dependency><groupId>org.springframework</groupId><artifactId>spring-jdbc</artifactId><version>4.3.12.RELEASE</version>
</dependency>

(2)创建配置类

package com.xiang.spring.tx;import com.mchange.v2.c3p0.ComboPooledDataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.core.JdbcTemplate;
import javax.sql.DataSource;
import java.beans.PropertyVetoException;/**
* 声明式事务:
*
* 环境搭建:
*  1.导入相关依赖
*      数据源、数据库驱动、SpringJDBC模块。
*  2.配置数据源和JdkcTemplate(spring提供的简化数据库操作的工具)操作数据库
*
*/
@ComponentScan("com.xiang.spring.tx")
@Configuration
public class TxConfig {// 数据源@Beanpublic DataSource dataSource() throws PropertyVetoException {ComboPooledDataSource dataSource = new ComboPooledDataSource();dataSource.setUser("root");dataSource.setPassword("123698745");dataSource.setDriverClass("com.mysql.jdbc.Driver");dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/test");return dataSource;}/*** JdbcTemplate操作数据库* spring对@Configuration配置文件有特殊处理,给容器中添加组件的方法,多次调用都是从容器中找组件,组件只会创建一次。*/@Beanpublic JdbcTemplate jdbcTemplate() throws PropertyVetoException {JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource());return jdbcTemplate;}
}

(3)添加service类和dao类

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;@Service
public class UserService {@Autowiredprivate UserDao userDao;public void insetUser() {userDao.insert();System.out.println("插入完成");}
}
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;import java.util.UUID;@Repository
public class UserDao {@Autowiredprivate JdbcTemplate jdbcTemplate;public void insert() {String sql = "insert into t_user(username, age) values(?, ?)";String username = UUID.randomUUID().toString().substring(0, 5);jdbcTemplate.update(sql, username, 19);}
}

(4)测试类查看结果

import com.xiang.spring.tx.TxConfig;
import com.xiang.spring.tx.UserService;
import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;public class IOCTest_Tx {@Testpublic void test01() {// 创建ioc容器,容器创建时,默认会将单例的bean都创建出来AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(TxConfig.class);UserService userService = applicationContext.getBean(UserService.class);userService.insetUser();}
}

2、事务添加

(1)给方法上标注@Transactional,标明这个方法是一个事务方法

/**
* 告诉spring这个方法是一个事务方法
*/
@Transactional
public void insetUser() {userDao.insert();System.out.println("插入完成");int i = 10/0;
}

(2)@EnableTransactionManagement开启基于注解的事务管理功能

@EnableTransactionManagement
@ComponentScan("com.xiang.spring.tx")
@Configuration
public class TxConfig {

(3)配置事务管理器来管理事务PlatformTransactionManager

/**
* 在容器中注册事务管理器
*/
@Bean
public PlatformTransactionManager platformTransactionManager() throws PropertyVetoException {DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager(dataSource());return dataSourceTransactionManager;
}

(4)如果事务方法报错,就会回滚。

二、声明式事务源码分析

1、原理(与AOP非常相似)

(1)@EnableTransactionManagement利用TransactionManagementConfigurationSelector给容器中导入组件。

导入两个组件AutoProxyRegistrar、ProxyTransactionManagementConfiguration。

(2)AutoProxyRegistrar给容器中注册一个InfrastructureAdvisorAutoProxyCreator组件。

① InfrastructureAdvisorAutoProxyCreator的作用只是利用后置处理器机制在对象创建以后,包装对象,返回一个代理对象(增强器),代理对象执行方法利用拦截器链进行调用。(与AOP类似)

(3)ProxyTransactionManagementConfiguration 做了什么?

① 给容器中注册事务增强器。

① 事务增强器要用事务注解的信息。用AnnotationTransactionAttributeSource解析事务注解。

② 事务拦截器。

TransactionInterceptor保存了事务的属性信息以及 事务管理器。

TransactionInterceptor是一个MethodInterceptor方法拦截器。

TransactionInterceptor在目标方法执行的时候,执行拦截器链,只有一个事务拦截器。

① 先获取事务的属性。

② 再获取PlatformTransactionManager(平台事务管理器),如果事先没有添加指定任何TransactionManager,最终会从容器中按照类型获取一个PlatformTransactionManager。

③ 执行目标方法,如果异常,获取到事务管理器,利用事务管理器回滚这次操作。

④ 如果正常,利用事务管理器提交事务。

(1)TransactionManagementConfigurationSelector的selectImports方法

@Override
protected String[] selectImports(AdviceMode adviceMode) {switch (adviceMode) {case PROXY: // 默认就是PROXYreturn new String[] {AutoProxyRegistrar.class.getName(), ProxyTransactionManagementConfiguration.class.getName()};case ASPECTJ:return new String[] {TransactionManagementConfigUtils.TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME};default:return null;}
}

(2)ProxyTransactionManagementConfiguration

package org.springframework.transaction.annotation;import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Role;
import org.springframework.transaction.config.TransactionManagementConfigUtils;
import org.springframework.transaction.interceptor.BeanFactoryTransactionAttributeSourceAdvisor;
import org.springframework.transaction.interceptor.TransactionAttributeSource;
import org.springframework.transaction.interceptor.TransactionInterceptor;/**
* {@code @Configuration} class that registers the Spring infrastructure beans
* necessary to enable proxy-based annotation-driven transaction management.
*
* @author Chris Beams
* @since 3.1
* @see EnableTransactionManagement
* @see TransactionManagementConfigurationSelector
*/
@Configuration
public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {@Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)@Role(BeanDefinition.ROLE_INFRASTRUCTURE)public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor() {BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();advisor.setTransactionAttributeSource(transactionAttributeSource());advisor.setAdvice(transactionInterceptor());advisor.setOrder(this.enableTx.<Integer>getNumber("order"));return advisor;}@Bean@Role(BeanDefinition.ROLE_INFRASTRUCTURE)public TransactionAttributeSource transactionAttributeSource() {return new AnnotationTransactionAttributeSource();}@Bean@Role(BeanDefinition.ROLE_INFRASTRUCTURE)public TransactionInterceptor transactionInterceptor() {TransactionInterceptor interceptor = new TransactionInterceptor();interceptor.setTransactionAttributeSource(transactionAttributeSource());if (this.txManager != null) {interceptor.setTransactionManager(this.txManager);}return interceptor;}
}

(3)TransactionAspectSupport的invokeWithinTransaction

protected Object invokeWithinTransaction(Method method, Class<?> targetClass, final InvocationCallback invocation)throws Throwable {// If the transaction attribute is null, the method is non-transactional.final TransactionAttribute txAttr = getTransactionAttributeSource().getTransactionAttribute(method, targetClass);final PlatformTransactionManager tm = determineTransactionManager(txAttr);final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) {// Standard transaction demarcation with getTransaction and commit/rollback calls.TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);Object retVal = null;try {// This is an around advice: Invoke the next interceptor in the chain.// This will normally result in a target object being invoked.retVal = invocation.proceedWithInvocation();}catch (Throwable ex) {// target invocation exceptioncompleteTransactionAfterThrowing(txInfo, ex);throw ex;}finally {cleanupTransactionInfo(txInfo);}commitTransactionAfterReturning(txInfo);return retVal;}else {// It's a CallbackPreferringPlatformTransactionManager: pass a TransactionCallback in.try {Object result = ((CallbackPreferringPlatformTransactionManager) tm).execute(txAttr,new TransactionCallback<Object>() {@Overridepublic Object doInTransaction(TransactionStatus status) {TransactionInfo txInfo = prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);try {return invocation.proceedWithInvocation();}catch (Throwable ex) {if (txAttr.rollbackOn(ex)) {// A RuntimeException: will lead to a rollback.if (ex instanceof RuntimeException) {throw (RuntimeException) ex;}else {throw new ThrowableHolderException(ex);}}else {// A normal return value: will lead to a commit.return new ThrowableHolder(ex);}}finally {cleanupTransactionInfo(txInfo);}}});// Check result: It might indicate a Throwable to rethrow.if (result instanceof ThrowableHolder) {throw ((ThrowableHolder) result).getThrowable();}else {return result;}}catch (ThrowableHolderException ex) {throw ex.getCause();}}
}

(4)TransactionAspectSupport的completeTransactionAfterThrowing,利用事务管理器回滚

protected void completeTransactionAfterThrowing(TransactionInfo txInfo, Throwable ex) {if (txInfo != null && txInfo.hasTransaction()) {if (logger.isTraceEnabled()) {logger.trace("Completing transaction for [" + txInfo.getJoinpointIdentification() +"] after exception: " + ex);}if (txInfo.transactionAttribute.rollbackOn(ex)) {try {txInfo.getTransactionManager().rollback(txInfo.getTransactionStatus());}catch (TransactionSystemException ex2) {logger.error("Application exception overridden by rollback exception", ex);ex2.initApplicationException(ex);throw ex2;}catch (RuntimeException ex2) {logger.error("Application exception overridden by rollback exception", ex);throw ex2;}catch (Error err) {logger.error("Application exception overridden by rollback error", ex);throw err;}}else {// We don't roll back on this exception.// Will still roll back if TransactionStatus.isRollbackOnly() is true.try {txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());}catch (TransactionSystemException ex2) {logger.error("Application exception overridden by commit exception", ex);ex2.initApplicationException(ex);throw ex2;}catch (RuntimeException ex2) {logger.error("Application exception overridden by commit exception", ex);throw ex2;}catch (Error err) {logger.error("Application exception overridden by commit error", ex);throw err;}}}
}

(5)TransactionAspectSupport的commitTransactionAfterReturning 事务提交

protected void commitTransactionAfterReturning(TransactionInfo txInfo) {if (txInfo != null && txInfo.hasTransaction()) {if (logger.isTraceEnabled()) {logger.trace("Completing transaction for [" + txInfo.getJoinpointIdentification() + "]");}txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());}
}

spring系列-注解驱动原理及源码-声明式事务使用及原理解析相关推荐

  1. Spring源码——声明式事务流程

    前言 最近回顾了一下Spring源码,准备用思维导图的方式简单的将整个源码内容的流程展示出来,思维导图.图片等文件更新在https://github.com/MrSorrow/spring-frame ...

  2. 手撸Spring系列12:MyBatis(源码篇)

    说在前头: 笔者本人为大三在读学生,书写文章的目的是为了对自己掌握的知识和技术进行一定的记录,同时乐于与大家一起分享,因本人资历尚浅,发布的文章难免存在一些错漏之处,还请阅读此文章的大牛们见谅与斧正. ...

  3. 框架源码专题:Spring声明式事务Transactional的原理

    文章目录 1. @Transactional的使用 2. spring事务的原理 2.1 开启事务,注册bean的后置处理器和相关bean对象,封装Advisor 2.2 匹配并创建动态代理 2.3 ...

  4. spring系列-注解驱动原理及源码-自动装配

    目录 一.spring规范的bean自动注入 1.使用@Autowired自动注入 2.使用@Qualifier指定需要装配的组件 3.使用@Autowired装配null对象 4.使用@Primar ...

  5. spring系列-注解驱动原理及源码-AOP使用及源码解析

    目录 一.用注解方式开启AOP 1.实例 2.AOP简单小结 二.AOP原理 1.@EnableAspectJAutoProxy溯源 2.AnnotationAwareAspectJAutoProxy ...

  6. spring系列-注解驱动原理及源码-bean生命周期

    目录 一.Bean的初始化和销毁 1.@Bean指定初始化和销毁方法 2.通过实现InitializingBean和Disposabean来初始化和销毁bean 3.使用JSR250定义的@PostC ...

  7. spring系列-注解驱动原理及源码-bean组件注册

    目录 一.环境初始化 1.环境准备 二.bean的手动注入 1.xml方式注入bean 2.使用@Configuration&@Bean方式注入bean 三.自动扫描注册组件及bean 1.使 ...

  8. spring系列-注解驱动原理及源码-spring容器创建流程

    目录 一.spring容器的refresh()[创建刷新] 二.BeanFactory 的创建及预准备工作 1.prepareRefresh()刷新前预处理工作. 2.obtainFreshBeanF ...

  9. spring系列-注解驱动原理及源码-属性赋值

    目录 一.bean属性赋值 1.bean属性使用@Value赋值 2.bean属性通过配置文件赋值 一.bean属性赋值 1.bean属性使用@Value赋值 (1)编写bean类 package c ...

最新文章

  1. 技术选型之Docker容器引擎
  2. 思考:用开发移动app的观念来开发网站
  3. H5实例教学--微信内嵌视频1(案例浅析)
  4. Tokyo Tyrant的下工具的使用
  5. SpringCloud从入门到进阶(九)——单点部署Zuul的压力测试与调优(二)
  6. postgreSQL分页
  7. mysql xtrabackup 保护模式_MySQL Xtrabackup备份原理和实现细节
  8. 5.1傅里叶展开,傅里叶级数推导--非常棒
  9. 联想计算机不能使用ghost,联想电脑不能GHOST的解决方法
  10. 计算机设备硬件维护税收编码,自动化设备的税收编码是多少
  11. 【交换机在江湖】第十二章 VLAN基础篇
  12. Android自定义View——动态ProgressBar之模仿360加速球
  13. UVM入门与进阶学习笔记1——UVM概述、类库地图、工厂机制、覆盖方法
  14. YoutubeDNN召回的一些问题
  15. 电脑为何连不上手机开的热点
  16. c语言oj猜灯谜,元宵节灯谜——文学典籍类
  17. 【第68篇】多目标跟踪:文献综述
  18. 1996年第26届亚特兰大奥运会会歌
  19. netpc安装使用手册(转)
  20. 周志华点评机器学习会议

热门文章

  1. Redis 的缓存异常处理 —— 缓存雪崩、缓存击穿、缓存穿透
  2. 「后端小伙伴来学前端了」关于 Vue中 Slot 插槽的使用,实用且也是组件中必会的一个知识,另外也可以实现父子组件之间通信
  3. Android实现顶层全局窗口,不依赖于Activity的Android全局悬浮窗的实现
  4. python保存文件到指定文件夹_python实现指定文件夹下的指定文件移动到指定位置...
  5. swiper 滚回第一个数据_名企必备的数据分析基础技能:Python大法(一)
  6. 笔记本网络计算机和设备不可见,WIN10局域网电脑和设备显示不完整
  7. python高斯滤波和降噪_高斯滤波原理及python实现
  8. 吸水间最低动水位标高_消防水泵-吸水管路设置要求
  9. sql order by 降序_数仓面试|四个在工作后才知道的SQL密技
  10. c++ vector 赋值_Vector 源码剖析