- 三哥
内容来自【自学星球】
欢迎大家来了解我的星球,和星主(也就是我)一起学习 Java ,深入 Java 体系中的所有技术。我给自己定的时间是一年,无论结果如何,必定能给星球中的各位带来点东西。
想要了解更多,欢迎访问👉:自学星球
--------------SSM系列源码文章及视频导航--------------
创作不易,望三连支持!
SSM源码解析视频
👉点我
Spring
- Spring 中注入 Bean 的各种骚操作做
- Spring 中Bean的生命周期及后置处理器使用
- Spring 中容器启动分析之refresh方法执行之前
- Spring refresh 方法分析之一
- Spring refresh 方法之二 invokeBeanFactoryPostProcessors 方法解析
- Spring refresh 方法分析之三
- Spring refresh 方法之四 finishBeanFactoryInitialization 分析
- Spring AOP源码分析一
- Spring AOP源码分析二
- Spring 事务源码分析
SpringMVC
MyBatis
- MyBatis 源码分析之 SqlSessionFactory 创建
- MyBatis 源码分析之 SqlSession 创建
- MyBatis 源码分析之 Mapper 接口代理对象生成及方法执行
- MyBatis 源码分析之 Select 语句执行(上)
- MyBatis 源码分析之 Select 语句执行(下)
- MyBatis 源码分析一二级缓存
---------------------【End】--------------------
一、简单使用
在这里使用声明式事物案例。
1、引入依赖
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
<!--mysql-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.25</version>
</dependency>
<!--阿里连接池-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.8</version>
</dependency>
2、编写 JDBC 配置文件
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://127.0.0.1:3306/my_utils?useUnicode=true&useSSL=false&characterEncoding=utf8&allowMultiQueries=true&serverTimezone=Asia/Shanghai
jdbc.username=root
jdbc.password=root
3、编写配置类
@EnableTransactionManagement // 开启事物
@Configuration
@ComponentScan("cn.j3code.studyspring.transactional")
@PropertySource("classpath:jdbc.properties")
public class MyTransactionalConfig {
@Value("${jdbc.driver}")
private String driver;
@Value("${jdbc.url}")
private String url;
@Value("${jdbc.username}")
private String username;
@Value("${jdbc.password}")
private String password;
// 数据库连接池
@Bean
public DruidDataSource getDataSource(){
DruidDataSource druidDataSource = new DruidDataSource();
druidDataSource.setUrl(url);
druidDataSource.setDriverClassName(driver);
druidDataSource.setUsername(username);
druidDataSource.setPassword(password);
return druidDataSource;
}
// 数据库操作对象
@Bean
public JdbcTemplate getJdbcTemplate(DruidDataSource druidDataSource){
JdbcTemplate jdbcTemplate = new JdbcTemplate();
jdbcTemplate.setDataSource(druidDataSource);
return jdbcTemplate;
}
// 事物管理器
@Bean
public DataSourceTransactionManager getTransactional(DruidDataSource druidDataSource){
DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager();
dataSourceTransactionManager.setDataSource(druidDataSource);
return dataSourceTransactionManager;
}
}
4、业务类
public interface IUserService {
void add(User user);
void update(User user);
}
@Service
public class UserServiceImpl implements IUserService {
@Autowired
private JdbcTemplate jdbcTemplate;
@Transactional // 事物注解
@Override
public void add(User user) {
int update = jdbcTemplate.update("insert into t_user(name,age) values(?,?)", user.getName(), user.getAge());
user = jdbcTemplate.queryForObject("select * from t_user where name = '" + user.getName() + "'", User.class);
System.out.println("查询结果:" + user);
update(user);
}
@Override
public void update(User user) {
int update = jdbcTemplate.update("update t_user set age = ? where id = ?", user.getAge(), user.getId());
}
}
5、测试
public class MyTransactionalMain {
public static void main(String[] args) {
// 读取配置文件启动
AnnotationConfigApplicationContext annotationApplicationContext =
new AnnotationConfigApplicationContext(MyTransactionalConfig.class);
IUserService bean = annotationApplicationContext.getBean(IUserService.class);
User user = new User();
user.setName("J3");
user.setAge(18);
bean.add(user);
}
}
细心的同学应该知道,如果程序中不加 @EnableTransactionManagement 注解,那么我们这个测试案例中事物相关的特性就不会生效,所以下面我们就以这个为切入点开始进入事物源码的分析。
二、@EnableTransactionManagement
注解源码:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(TransactionManagementConfigurationSelector.class)
public @interface EnableTransactionManagement {
/**
* 指定使用什么代理模式(true为cglib代理,false 为jdk代理)
*/
boolean proxyTargetClass() default false;
/**
* 通知模式 是使用代理模式还是aspectj 我们一般使用Proxy
*/
AdviceMode mode() default AdviceMode.PROXY;
/**
* Indicate the ordering of the execution of the transaction advisor
* when multiple advices are applied at a specific joinpoint.
* <p>The default is {@link Ordered#LOWEST_PRECEDENCE}.
*/
int order() default Ordered.LOWEST_PRECEDENCE;
}
又看到了个非常熟悉的 @Import 注解,向 IOC 容器中导入 TransactionManagementConfigurationSelector 类。
该类源码:
public class TransactionManagementConfigurationSelector extends AdviceModeImportSelector<EnableTransactionManagement> {
@Override
protected String[] selectImports(AdviceMode adviceMode) {
switch (adviceMode) {
// 如果基于代理模式
case PROXY:
return new String[] {AutoProxyRegistrar.class.getName(), ProxyTransactionManagementConfiguration.class.getName()};
// 如果基于ASPECTJ
case ASPECTJ:
return new String[] {TransactionManagementConfigUtils.TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME};
default:
return null;
}
}
}
因为 @EnableTransactionManagement 注解如果不设置 mode ,则使用默认的 PROXY 模式,反之则是 ASPECTJ 模式。
这里,我们只讨论代理的方式实现事物,所以会走下面这个代码。
return new String[] {AutoProxyRegistrar.class.getName(), ProxyTransactionManagementConfiguration.class.getName()};
2.1 AutoProxyRegistrar
先来看看 AutoProxyRegistrar 源码:
public class AutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
private final Log logger = LogFactory.getLog(getClass());
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
boolean candidateFound = false;
// 从我们传入进去的配置类上获取所有的注解的
Set<String> annoTypes = importingClassMetadata.getAnnotationTypes();
// 循环我们上一步获取的注解
for (String annoType : annoTypes) {
// 获取注解的元信息
AnnotationAttributes candidate = AnnotationConfigUtils.attributesFor(importingClassMetadata, annoType);
if (candidate == null) {
continue;
}
// 获取注解的mode属性
Object mode = candidate.get("mode");
// 获取注解的proxyTargetClass
Object proxyTargetClass = candidate.get("proxyTargetClass");
// 根据mode和proxyTargetClass的判断来注册不同的组件
if (mode != null && proxyTargetClass != null && AdviceMode.class == mode.getClass() &&
Boolean.class == proxyTargetClass.getClass()) {
candidateFound = true;
if (mode == AdviceMode.PROXY) {
// 重点进入到这一步
AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);
if ((Boolean) proxyTargetClass) {
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
return;
}
}
}
}
if (!candidateFound && logger.isInfoEnabled()) {
String name = getClass().getSimpleName();
logger.info(String.format("%s was imported but no annotations were found " +
"having both 'mode' and 'proxyTargetClass' attributes of type " +
"AdviceMode and boolean respectively. This means that auto proxy " +
"creator registration and configuration may not have occurred as " +
"intended, and components may not be proxied as expected. Check to " +
"ensure that %s has been @Import'ed on the same class where these " +
"annotations are declared; otherwise remove the import of %s " +
"altogether.", name, name, name));
}
}
}
该方法会获取传入进来的 class 上标注的注解,并循环获取到的注解进行判断,如果是事物相关的注解则会进入 registerAutoProxyCreatorIfNecessary 方法,该方法会向容器中注册事物自动代理创建器类。
进入registerAutoProxyCreatorIfNecessary 方法源码:
org.springframework.aop.config.AopConfigUtils#registerAutoProxyCreatorIfNecessary
public static BeanDefinition registerAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry) {
return registerAutoProxyCreatorIfNecessary(registry, null);
}
org.springframework.aop.config.AopConfigUtils#registerAutoProxyCreatorIfNecessary
public static BeanDefinition registerAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry,
@Nullable Object source) {
// 注册自动代理创建器
return registerOrEscalateApcAsRequired(InfrastructureAdvisorAutoProxyCreator.class, registry, source);
}
在 AOP 中向容器中注册的自动代理创建器是 AnnotationAwareAspectJAutoProxyCreator ,而在此事物自动创建代理器则是 InfrastructureAdvisorAutoProxyCreator 。
在 AopConfigUtils 中标注了所有支持的自动代理创建类,根据其代码可以判断优先级如下:
代码
public abstract class AopConfigUtils {
private static final List<Class<?>> APC_PRIORITY_LIST = new ArrayList<>();
/**
* Setup the escalation list.
*/
static {
APC_PRIORITY_LIST.add(InfrastructureAdvisorAutoProxyCreator.class);
APC_PRIORITY_LIST.add(AspectJAwareAdvisorAutoProxyCreator.class);
APC_PRIORITY_LIST.add(AnnotationAwareAspectJAutoProxyCreator.class);
}
}
优先级:
InfrastructureAdvisorAutoProxyCreator < AspectJAwareAdvisorAutoProxyCreator < AnnotationAwareAspectJAutoProxyCreator
下面我们来看看 InfrastructureAdvisorAutoProxyCreator 的类继承结构图
由图可知,该类实现了 BeanPostProcessor 接口,则其会作用于每个 Bean 的初始化前后。在每个 bean 初始化前调用 postProcessBeforeInitialization,初始化后调用 postProcessAfterInitialization 。
2.2 ProxyTransactionManagementConfiguration
该类源码:
public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {
/**
* 为我我们容器中导入了
* beanName为org.springframework.transaction.config.internalTransactionAdvisor
* 类型为BeanFactoryTransactionAttributeSourceAdvisor
* 的增强器
*/
@Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor() {
BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();
advisor.setTransactionAttributeSource(transactionAttributeSource());
advisor.setAdvice(transactionInterceptor());
if (this.enableTx != null) {
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;
}
}
ProxyTransactionManagementConfiguration 很明显就是一个事物相关的配置类,该类向 IOC 容器中注册了三个 bean:
- BeanFactoryTransactionAttributeSourceAdvisor:增强器
- TransactionAttributeSource:事物属性源
- TransactionInterceptor:事物拦截器
可以说,事物相关的功能离不开这三个类的互相作用,下面依次分析这三个类。
2.2.1 BeanFactoryTransactionAttributeSourceAdvisor
先看一下该类继承结构图:
BeanFactoryTransactionAttributeSourceAdvisor
是 Advisor
子类,那么我们可以知道其中有两个关键属性: Pointcut(判断是否可以作用于当前方法)
和 Advice(作用于当前方法的具体逻辑)
。
那我们来看看 Pointcut 是如何生效的。
再分析 Pointcut 生效前,我们先明确一件事情,Spring 事物也是通过 AOP 代理的方式实现的。那么要判断一个 Bean 是否需要代理,肯定也是走 AOP 代理的流程,通过遍历程序中所有的增强对象进行挨个判断,匹配了那么就是需要进行代理。
那,这就回顾到 AOP 代理的流程了,循环程序中的增强对象进行挨个判断的程序如下:
org.springframework.aop.support.AopUtils#findAdvisorsThatCanApply
public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) {
// ...
// 循环程序中的所有增强对象
for (Advisor candidate : candidateAdvisors) {
if (candidate instanceof IntroductionAdvisor) {
// already processed
continue;
}
// 挨个判断增强是否生效
if (canApply(candidate, clazz, hasIntroductions)) {
eligibleAdvisors.add(candidate);
}
}
// ...
}
canApply 最终会通过调用 Pointcut 中的 matches 方法进行判断,那么怎会来到我们事物增强对象中的这个代理:
public class BeanFactoryTransactionAttributeSourceAdvisor extends AbstractBeanFactoryPointcutAdvisor {
// 初始化事物增强判断对象 pointcut
private final TransactionAttributeSourcePointcut pointcut = new TransactionAttributeSourcePointcut() {
@Override
@Nullable
protected TransactionAttributeSource getTransactionAttributeSource() {
return transactionAttributeSource;
}
};
}
org.springframework.transaction.interceptor.TransactionAttributeSourcePointcut#matches
public boolean matches(Method method, @Nullable Class<?> targetClass) {
if (targetClass != null && TransactionalProxy.class.isAssignableFrom(targetClass)) {
return false;
}
// 获取 ProxyTransactionManagementConfiguration 配置类中配置的 AnnotationTransactionAttributeSource 对象
TransactionAttributeSource tas = getTransactionAttributeSource();
// 调用 AnnotationTransactionAttributeSource # getTransactionAttribute 方法进行事物解析
return (tas == null || tas.getTransactionAttribute(method, targetClass) != null);
}
我们可以看到最终会调用 getTransactionAttribute 方法,如果该方法返回一个对象说明该方法或 class 需要增强。
2.2.2 AnnotationTransactionAttributeSource
该类继承结构图如下:
由 2.2.1 节可知,matches 方法会调用其 getTransactionAttribute 方法来找到类或方法的事物相关功能,而我们再源码中并没有发现 getTransactionAttribute ,而是在其父类 AbstractFallbackTransactionAttributeSource 中找到该方法的调用。
源码:
org.springframework.transaction.interceptor.AbstractFallbackTransactionAttributeSource#getTransactionAttribute
public TransactionAttribute getTransactionAttribute(Method method, @Nullable Class<?> targetClass) {
if (method.getDeclaringClass() == Object.class) {
// 如果目标方法是内置类Object上的方法,总是返回null,这些方法上不应用事务
return null;
}
// 先查看针对该方法是否已经获取过其注解事务属性并且已经缓存
Object cacheKey = getCacheKey(method, targetClass);
TransactionAttribute cached = this.attributeCache.get(cacheKey);
if (cached != null) {
// 目标方法上的事务注解属性信息已经缓存的情况
// or an actual transaction attribute.
if (cached == NULL_TRANSACTION_ATTRIBUTE) {
// 目标方法上上并没有事务注解属性,但是已经被尝试分析过并且已经被缓存,
// 使用的值是 NULL_TRANSACTION_ATTRIBUTE,所以这里再次尝试获取其注解事务属性时,
// 直接返回 null
return null;
}
else {
// 返回所缓存的注解事务属性
return cached;
}
}
else {
// 目标方法上的注解事务属性尚未分析过,现在分析获取
TransactionAttribute txAttr = computeTransactionAttribute(method, targetClass);
if (txAttr == null) {
// 如果目标方法上并没有使用注解事务属性,也缓存该信息,只不过使用的值是一个特殊值:
this.attributeCache.put(cacheKey, NULL_TRANSACTION_ATTRIBUTE);
}
else {
// 目标方法上使用了注解事务属性,将其放到缓存
String methodIdentification = ClassUtils.getQualifiedMethodName(method, targetClass);
if (txAttr instanceof DefaultTransactionAttribute) {
((DefaultTransactionAttribute) txAttr).setDescriptor(methodIdentification);
}
if (logger.isTraceEnabled()) {
logger.trace("Adding transactional method '" + methodIdentification + "' with attribute: " + txAttr);
}
this.attributeCache.put(cacheKey, txAttr);
}
return txAttr;
}
该方法执行流程非常简单,先从缓存中获取我们想要的对象,如果存在,直接返回,反之则调用 computeTransactionAttribute 方法进行查找,最后放入缓存并返回结果。
那么,接下来就看看 computeTransactionAttribute 方法源码:
org.springframework.transaction.interceptor.AbstractFallbackTransactionAttributeSource#computeTransactionAttribute
protected TransactionAttribute computeTransactionAttribute(Method method, @Nullable Class<?> targetClass) {
// 如果事务注解属性分析仅仅针对public方法,而当前方法不是public,则直接返回null
if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) {
return null;
}
// Ignore CGLIB subclasses - introspect the actual user class.
// 参数 method 可能是基于接口的方法,该接口和参数targetClass所对应的类不同(也就是说:
// targetClass是相应接口的某个实现类),而我们这里需要的属性是要来自targetClass的,
// 所以这里先获取targetClass上的那个和method对应的方法,这里 method, specificMethod
// 都可以认为是潜在的目标方法
Class<?> userClass = (targetClass != null ? ClassUtils.getUserClass(targetClass) : null);
// The method may be on an interface, but we need attributes from the target class.
// If the target class is null, the method will be unchanged.
Method specificMethod = ClassUtils.getMostSpecificMethod(method, userClass);
// If we are dealing with method with generic parameters, find the original method.
specificMethod = BridgeMethodResolver.findBridgedMethod(specificMethod);
// 首先尝试检查事务注解属性直接标记在目标方法 specificMethod 上
TransactionAttribute txAttr = findTransactionAttribute(specificMethod);
if (txAttr != null) {
// 事务注解属性直接标记在目标方法上
return txAttr;
}
// 然后尝试检查事务注解属性是否标记在目标方法 specificMethod 所属类上
txAttr = findTransactionAttribute(specificMethod.getDeclaringClass());
if (txAttr != null && ClassUtils.isUserLevelMethod(method)) {
// 事务注解属性是否标记在目标方法所属类上
return txAttr;
}
// 逻辑走到这里说明目标方法specificMethod,也就是实现类上的目标方法上没有标记事务注解属性
if (specificMethod != method) {
// 如果 specificMethod 和 method 不同,则说明 specificMethod 是具体实现类
// 的方法,method 是实现类所实现接口的方法,现在尝试从 method 上获取事务注解属性
txAttr = findTransactionAttribute(method);
if (txAttr != null) {
return txAttr;
}
// 现在尝试在 method 所属类上查看是否有事务注解属性
txAttr = findTransactionAttribute(method.getDeclaringClass());
if (txAttr != null && ClassUtils.isUserLevelMethod(method)) {
return txAttr;
}
}
// specificMethod 方法/所属类上没有事务注解属性,
// method 方法/所属类上也没有事务注解属性,
// 所以返回 null
return null;
}
该方法分类很多种类型获取事物注解属性:
- 目标方法上
- 目标方法所属类上
- 目标接口方法上
- 目标接口方法所属类上
以上这四种,有一个找到事物相关属性则直接返回。那么具体是如何找的,就要进入 findTransactionAttribute 方法具体看看了。
org.springframework.transaction.annotation.AnnotationTransactionAttributeSource#findTransactionAttribute(java.lang.reflect.Method)
protected TransactionAttribute findTransactionAttribute(Method method) {
return determineTransactionAttribute(method);
}
org.springframework.transaction.annotation.AnnotationTransactionAttributeSource#determineTransactionAttribute
/**
* 分析获取某个被注解的元素,具体的来讲,指的是一个类或者一个方法上的事务注解属性。
* 该实现会遍历自己属性annotationParsers中所包含的事务注解属性分析器试图获取事务注解属性,
* 一旦获取到事务注解属性则返回,如果获取不到则返回null,表明目标类/方法上没有事务注解。
*/
protected TransactionAttribute determineTransactionAttribute(AnnotatedElement ae) {
for (TransactionAnnotationParser annotationParser : this.annotationParsers) {
TransactionAttribute attr = annotationParser.parseTransactionAnnotation(ae);
if (attr != null) {
return attr;
}
}
return null;
}
org.springframework.transaction.annotation.SpringTransactionAnnotationParser#parseTransactionAnnotation(java.lang.reflect.AnnotatedElement)
public TransactionAttribute parseTransactionAnnotation(AnnotatedElement ae) {
// 查找 ae 对象上是否由 Transactional.class 相关信息
AnnotationAttributes attributes = AnnotatedElementUtils.findMergedAnnotationAttributes(
ae, Transactional.class, false, false);
// 存在 Transactional 注解信息
if (attributes != null) {
// 封装 Transactional 注解信息,并返回
return parseTransactionAnnotation(attributes);
}
else {
return null;
}
}
在这里我们看到了最想看到的东西了,就是判断是否有 Transactional 注解标注的信息,如果有 findMergedAnnotationAttributes 方法会返回其对应的对象,并通过 parseTransactionAnnotation 解析该对象然后返回封装的结果。
org.springframework.transaction.annotation.SpringTransactionAnnotationParser#parseTransactionAnnotation(org.springframework.core.annotation.AnnotationAttributes)
protected TransactionAttribute parseTransactionAnnotation(AnnotationAttributes attributes) {
//这个地方事务属性对象是有很多默认值的,它继承自DefaultTransactionDefinition
RuleBasedTransactionAttribute rbta = new RuleBasedTransactionAttribute();
// 传播
Propagation propagation = attributes.getEnum("propagation");
rbta.setPropagationBehavior(propagation.value());
// 隔离等级
Isolation isolation = attributes.getEnum("isolation");
rbta.setIsolationLevel(isolation.value());
// 超时时间
rbta.setTimeout(attributes.getNumber("timeout").intValue());
// 是否只读
rbta.setReadOnly(attributes.getBoolean("readOnly"));
// 事务管理器bean的名称
rbta.setQualifier(attributes.getString("value"));
ArrayList<RollbackRuleAttribute> rollBackRules = new ArrayList<>();
// 回滚相关配置
Class<?>[] rbf = attributes.getClassArray("rollbackFor");
for (Class<?> rbRule : rbf) {
RollbackRuleAttribute rule = new RollbackRuleAttribute(rbRule);
rollBackRules.add(rule);
}
String[] rbfc = attributes.getStringArray("rollbackForClassName");
for (String rbRule : rbfc) {
RollbackRuleAttribute rule = new RollbackRuleAttribute(rbRule);
rollBackRules.add(rule);
}
Class<?>[] nrbf = attributes.getClassArray("noRollbackFor");
for (Class<?> rbRule : nrbf) {
NoRollbackRuleAttribute rule = new NoRollbackRuleAttribute(rbRule);
rollBackRules.add(rule);
}
String[] nrbfc = attributes.getStringArray("noRollbackForClassName");
for (String rbRule : nrbfc) {
NoRollbackRuleAttribute rule = new NoRollbackRuleAttribute(rbRule);
rollBackRules.add(rule);
}
rbta.getRollbackRules().addAll(rollBackRules);
return rbta;
}
到这里,事务相关的信息已经被解析完成存放在 AnnotationTransactionAttributeSource 类体系当中了。而且有对象返回在 matches 方法中就会返回 true ,最后会走创建代理流程,至此我们的事务代理对象就完成了。
下面就是事务代理的执行了,在 TransactionInterceptor # invoke 方法中。
2.2.3 TransactionInterceptor
该类继承结构图:
TransactionInterceptor 是事务拦截器,当标注 @Transaction 注解的方法被执行时会来执行 invoke 方法,源码如下:
public class TransactionInterceptor extends TransactionAspectSupport implements MethodInterceptor, Serializable {
@Override
@Nullable
public Object invoke(final MethodInvocation invocation) throws Throwable {
// 获取代理对象的目标class
Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);
// 使用事务调用
return invokeWithinTransaction(invocation.getMethod(), targetClass, invocation::proceed);
}
}
进入 invokeWithinTransaction 方法:
protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass,
final InvocationCallback invocation) throws Throwable {
// 获取事务数据源,这里获取的数据源就是在 TransactionInterceptor 注入的时候的设置的属性transactionAttributeSource = AnnotationTransactionAttributeSource。
// 在 ProxyTransactionManagementConfiguration 中完成
TransactionAttributeSource tas = getTransactionAttributeSource();
// 获取对应的事务属性
final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);
// 获取一个合适的 TransactionManager
final PlatformTransactionManager tm = determineTransactionManager(txAttr);
// 构造方法的唯一标识( 全路径了类名.方法)
final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);
// 对不同事务情景的处理
// 声明式事务的处理
// 如果txAttr为空或者tm 属于非CallbackPreferringPlatformTransactionManager,执行目标增强
// 在TransactionManager上,CallbackPreferringPlatformTransactionManager实现PlatformTransactionManager接口,暴露出一个方法用于执行事务处理中的回调
if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) {
// 如果有必要,创建事务信息。主要由于事务的传播属性,所以这里并不一定会创建事务
TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);
Object retVal = null;
try {
// 执行被增强的方法
retVal = invocation.proceedWithInvocation();
}
catch (Throwable ex) {
// 异常回滚
completeTransactionAfterThrowing(txInfo, ex);
throw ex;
}
finally {
// 提交之前清除事务信息
cleanupTransactionInfo(txInfo);
}
// 提交事务
commitTransactionAfterReturning(txInfo);
return retVal;
}
// 编程式事务(CallbackPreferringPlatformTransactionManager)的处理。这里的逻辑基本都被封装了
else {
final ThrowableHolder throwableHolder = new ThrowableHolder();
// It's a CallbackPreferringPlatformTransactionManager: pass a TransactionCallback in.
try {
// 直接调用execute 方法。由于事务的提交回滚等操作都已经封装好了,所以这里并没有对事务进行详细的操作。
Object result = ((CallbackPreferringPlatformTransactionManager) tm).execute(txAttr, 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.
throwableHolder.throwable = ex;
return null;
}
}
finally {
// 清除事务信息
cleanupTransactionInfo(txInfo);
}
});
// Check result state: It might indicate a Throwable to rethrow.
if (throwableHolder.throwable != null) {
throw throwableHolder.throwable;
}
return result;
}
catch (ThrowableHolderException ex) {
throw ex.getCause();
}
catch (TransactionSystemException ex2) {
if (throwableHolder.throwable != null) {
logger.error("Application exception overridden by commit exception", throwableHolder.throwable);
ex2.initApplicationException(throwableHolder.throwable);
}
throw ex2;
}
catch (Throwable ex2) {
if (throwableHolder.throwable != null) {
logger.error("Application exception overridden by commit exception", throwableHolder.throwable);
}
throw ex2;
}
}
}
invokeWithinTransaction 方法分为两种情况执行:
- 声明式事务
- 编程式事务
这里,我们主要分析声明式事务的情况进行分析,所以主要就是一下几个步骤:
- createTransactionIfNecessary():创建事务(这里可能创建也可能不创建)
- invocation.proceedWithInvocation():执行目标方法
- completeTransactionAfterThrowing(txInfo, ex):异常,执行提交事务或回滚事务
- cleanupTransactionInfo(txInfo):清理当前线程事务信息
- commitTransactionAfterReturning(txInfo):方法执行成功,提交事务
三、事务执行流程
3.1 事务创建
源码:
org.springframework.transaction.interceptor.TransactionAspectSupport#createTransactionIfNecessary
// 若有需要 创建一个TransactionInfo (具体的事务从事务管理器里面getTransaction()出来~)
protected TransactionInfo createTransactionIfNecessary(@Nullable PlatformTransactionManager tm,
@Nullable TransactionAttribute txAttr, final String joinpointIdentification) {
// If no name specified, apply method identification as transaction name.
// 如果没有名称指定则使用方法唯一标识,并使用 DelegatingTransactionAttribute 包装 txAttr
if (txAttr != null && txAttr.getName() == null) {
txAttr = new DelegatingTransactionAttribute(txAttr) {
@Override
public String getName() {
return joinpointIdentification;
}
};
}
// 从事务管理器里,通过txAttr拿出来一个TransactionStatus
TransactionStatus status = null;
if (txAttr != null) {
if (tm != null) {
// 获取 TransactionStatus
status = tm.getTransaction(txAttr);
}
else {
if (logger.isDebugEnabled()) {
logger.debug("Skipping transactional joinpoint [" + joinpointIdentification +
"] because no transaction manager has been configured");
}
}
}
// 根据指定的属性与 status 等,转换成一个通用的TransactionInfo
return prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);
}
这个方法有两个逻辑:
- 获取事务状态
- 封装事务信息
先来看一下事务状态有哪些
DefaultTransactionStatus 是 TransactionStatus 的默认实现
public class DefaultTransactionStatus extends AbstractTransactionStatus {
// 封装的事务对象
private final Object transaction;
// 是否是新建的事务
private final boolean newTransaction;
// 是否是新的同步器
private final boolean newSynchronization;
// 是否是只读的
private final boolean readOnly;
// 是否能调试
private final boolean debug;
// 挂起了其他的事务后,这个用来保存挂起事务的信息;用来恢复使用;
private final Object suspendedResources;
// ...
}
再来看看事务传播值有哪些
public interface TransactionDefinition {
// 如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务中。这是最常见的选择。
int PROPAGATION_REQUIRED = 0;
// 支持当前事务,如果当前没有事务,就以非事务方式执行。
int PROPAGATION_SUPPORTS = 1;
// 使用当前的事务,如果当前没有事务,就抛出异常。
int PROPAGATION_MANDATORY = 2;
// 新建事务,如果当前存在事务,把当前事务挂起。
int PROPAGATION_REQUIRES_NEW = 3;
// 以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
int PROPAGATION_NOT_SUPPORTED = 4;
// 以非事务方式执行,如果当前存在事务,则抛出异常。
int PROPAGATION_NEVER = 5;
// 如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与PROPAGATION_REQUIRED类似的操作。
int PROPAGATION_NESTED = 6;
int ISOLATION_DEFAULT = -1;
// (读未提交)允许读取尚未提交的修改,可能导致脏读、幻读和不可重复读。
int ISOLATION_READ_UNCOMMITTED = Connection.TRANSACTION_READ_UNCOMMITTED;
// (读已提交)允许从已经提交的事务读取,可防止脏读、但幻读,不可重复读仍然有可能发生。
int ISOLATION_READ_COMMITTED = Connection.TRANSACTION_READ_COMMITTED;
// (重复读)对相同字段的多次读取的结果是一致的,除非数据被当前事务自生修改。可防止脏读和不可重复读,但幻读仍有可能发生。
int ISOLATION_REPEATABLE_READ = Connection.TRANSACTION_REPEATABLE_READ;
// (串行化)完全服从acid隔离原则,确保不发生脏读、不可重复读、和幻读,但执行效率最低。
int ISOLATION_SERIALIZABLE = Connection.TRANSACTION_SERIALIZABLE;
// 使用数据库默认的事务隔离级别。
int TIMEOUT_DEFAULT = -1;
}
ok,简单了解了这些相关内容之后,那我们来看看是如何获取事务状态信息的。
org.springframework.transaction.support.AbstractPlatformTransactionManager#getTransaction
public final TransactionStatus getTransaction(@Nullable TransactionDefinition definition)
throws TransactionException {
// 注解的信息
TransactionDefinition def = (definition != null ? definition : TransactionDefinition.withDefaults());
// 得到事务的封装对象
//doGetTransaction()方法是抽象方法,具体的实现由具体的事务处理器提供(下面会以DataSourceTransactionManager为例子)
Object transaction = doGetTransaction();
boolean debugEnabled = logger.isDebugEnabled();
//检查当前线程是否存在事务 isExistingTransaction此方法默认返回false 但子类都复写了此方法
if (isExistingTransaction(transaction)) {
// Existing transaction found -> check propagation behavior to find out how to behave.
// handleExistingTransaction方法为处理已经存在事务的情况
// 这个方法的实现也很复杂,总之还是对一些传播属性进行解析,各种情况的考虑~~~~~ 如果有新事务产生 doBegin()就会被调用~~~~
return handleExistingTransaction(def, transaction, debugEnabled);
}
// 如果注解设置的参数是不合法,抛异常
if (def.getTimeout() < TransactionDefinition.TIMEOUT_DEFAULT) {
throw new InvalidTimeoutException("Invalid transaction timeout", def.getTimeout());
}
// 处理事务属性中配置的事务传播特性==============
// PROPAGATION_MANDATORY 如果已经存在一个事务,支持当前事务。如果没有一个活动的事务,则抛出异常
if (def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) {
throw new IllegalTransactionStateException(
"No existing transaction found for transaction marked with propagation 'mandatory'");
}
//如果事务传播特性为required、required_new或nested
else if (def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED ||
def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW ||
def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
// 挂起,但是doSuspend()由子类去实现~~~
// 挂起操作,触发相关的挂起注册的事件,把当前线程事物的所有属性都封装好,放到一个SuspendedResourcesHolder
// 然后清空清空一下`当前线程事务`
SuspendedResourcesHolder suspendedResources = suspend(null);
if (debugEnabled) {
logger.debug("Creating new transaction with name [" + def.getName() + "]: " + def);
}
try {
boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
//创建一个新的事务状态 就是new DefaultTransactionStatus() 把个属性都赋值上
DefaultTransactionStatus status = newTransactionStatus(
definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
// 开启事物,抽象方法,由子类去实现~
doBegin(transaction, definition);
// 初始化事物同步属性
//初始化和同步事务状态 是TransactionSynchronizationManager这个类 它内部维护了很多的ThreadLocal
prepareSynchronization(status, definition);
return status;
}
catch (RuntimeException | Error ex) {
//重新开始 doResume由子类去实现
resume(null, suspendedResources);
throw ex;
}
}
// 走到这里 传播属性就是不需要事务的 那就直接创建一个
else {
// Create "empty" transaction: no actual transaction, but potentially synchronization.
if (def.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT && logger.isWarnEnabled()) {
logger.warn("Custom isolation level specified but no actual transaction initiated; " +
"isolation level will effectively be ignored: " + def);
}
// 这个方法相当于先newTransactionStatus,再prepareSynchronization这两步~~~
// 显然和上面的区别是:中间不回插入调用doBegin()方法,因为没有事务 begin个啥
boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
return prepareTransactionStatus(def, null, true, newSynchronization, debugEnabled, null);
}
}
总结一下该方法干了些啥:
- 获取事务封装对象
- 判断是否存在事务,存在则走事务存在逻辑
- 处理事务属性中配置的事务传播特性
- PROPAGATION_MANDATORY 情况下,抛错
- PROPAGATION_REQUIRED、PROPAGATION_REQUIRES_NEW 、PROPAGATION_NESTED 情况下
- 挂起空事务
- 新建一个事务
- 以非事务方式运行
接着,我们先来看看获取事务封装对象方法 doGetTransaction()
org.springframework.jdbc.datasource.DataSourceTransactionManager#doGetTransaction
protected Object doGetTransaction() {
// 新建一个事务的封装对象,主要是保存Connenct;
DataSourceTransactionObject txObject = new DataSourceTransactionObject();
txObject.setSavepointAllowed(isNestedTransactionAllowed());
// 通过事务事务同步器,得到曾经绑定的连接connect;
ConnectionHolder conHolder =
(ConnectionHolder) TransactionSynchronizationManager.getResource(obtainDataSource());
txObject.setConnectionHolder(conHolder, false);
return txObject;
}
TransactionSynchronizationManager 中都是用 ThreadLocal 进行存值。
下面看看判断是否存在事务方法 isExistingTransaction():
org.springframework.jdbc.datasource.DataSourceTransactionManager#isExistingTransaction
protected boolean isExistingTransaction(Object transaction) {
DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
return (txObject.hasConnectionHolder() && txObject.getConnectionHolder().isTransactionActive());
}
在事务封装的对象中有connect,连接的信息。如果是正在使用的事务,这个属性是true。
如果事务存在,那么则会进行 Spring 事务的传播行为逻辑中,对每个具体的传播行为做处理,方法为 handleExistingTransaction() 。
org.springframework.transaction.support.AbstractPlatformTransactionManager#handleExistingTransaction
private TransactionStatus handleExistingTransaction(
TransactionDefinition definition, Object transaction, boolean debugEnabled)
throws TransactionException {
// PROPAGATION_NEVER --> 以非事物方式执行,如果当前存在事物,则抛出异常。
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NEVER) {
throw new IllegalTransactionStateException(
"Existing transaction found for transaction marked with propagation 'never'");
}
// 以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NOT_SUPPORTED) {
if (debugEnabled) {
logger.debug("Suspending current transaction");
}
// 重点:挂起已有事物
Object suspendedResources = suspend(transaction);
boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
// 创建新事物,注意:transaction参数为null,所以这里创建的不是一个真正的事物
return prepareTransactionStatus(
definition, null, false, newSynchronization, debugEnabled, suspendedResources);
}
// 新建事务,如果当前存在事务,把当前事务挂起。
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW) {
if (debugEnabled) {
logger.debug("Suspending current transaction, creating new transaction with name [" +
definition.getName() + "]");
}
// 重点:挂起已有事物
SuspendedResourcesHolder suspendedResources = suspend(transaction);
try {
boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
// 创建事物
DefaultTransactionStatus status = newTransactionStatus(
definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
// 开启事物
doBegin(transaction, definition);
// 初始化事物同步属性
prepareSynchronization(status, definition);
return status;
}
catch (RuntimeException | Error beginEx) {
resumeAfterBeginException(transaction, suspendedResources, beginEx);
throw beginEx;
}
}
// 如果不允许嵌套事物,则抛出异常
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
if (!isNestedTransactionAllowed()) {
throw new NestedTransactionNotSupportedException(
"Transaction manager does not allow nested transactions by default - " +
"specify 'nestedTransactionAllowed' property with value 'true'");
}
if (debugEnabled) {
logger.debug("Creating nested transaction with name [" + definition.getName() + "]");
}
// 下面对JtaTransactionManager和AbstractPlatformTransactionManager分别进行处理
// useSavepointForNestedTransaction(),是否为嵌套事务使用保存点
// 对于JtaTransactionManager-->返回false
// 对于AbstractPlatformTransactionManager-->返回true
if (useSavepointForNestedTransaction()) {
// Create savepoint within existing Spring-managed transaction,
// through the SavepointManager API implemented by TransactionStatus.
// Usually uses JDBC 3.0 savepoints. Never activates Spring synchronization.
// 创建保存点在现有spring管理事务,通过TransactionStatus SavepointManager API实现。
// 通常使用JDBC 3.0保存点。永远不要激活Spring同步。
DefaultTransactionStatus status =
prepareTransactionStatus(definition, transaction, false, false, debugEnabled, null);
// 创建保存点
status.createAndHoldSavepoint();
return status;
}
else {
// Nested transaction through nested begin and commit/rollback calls.
// Usually only for JTA: Spring synchronization might get activated here
// in case of a pre-existing JTA transaction.
// 通过嵌套的开始,提交调用,及回滚调用进行嵌套事务。
// 只对JTA有效,如果已经存在JTA事务,这里可能会激活Spring同步。
boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
// 创建事物
DefaultTransactionStatus status = newTransactionStatus(
definition, transaction, true, newSynchronization, debugEnabled, null);
// 开启事物
doBegin(transaction, definition);
// 初始化事物同步属性
prepareSynchronization(status, definition);
return status;
}
}
// Assumably PROPAGATION_SUPPORTS or PROPAGATION_REQUIRED.
if (debugEnabled) {
logger.debug("Participating in existing transaction");
}
if (isValidateExistingTransaction()) {
// 验证事物隔离级别
// 如果当前事物的隔离级别不为默认隔离级别,则比较当前事物隔离级别与已有事物隔离级别,
// 如不同,则抛出事物隔离级别不兼容异常
if (definition.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT) {
Integer currentIsolationLevel = TransactionSynchronizationManager.getCurrentTransactionIsolationLevel();
if (currentIsolationLevel == null || currentIsolationLevel != definition.getIsolationLevel()) {
Constants isoConstants = DefaultTransactionDefinition.constants;
throw new IllegalTransactionStateException("Participating transaction with definition [" +
definition + "] specifies isolation level which is incompatible with existing transaction: " +
(currentIsolationLevel != null ?
isoConstants.toCode(currentIsolationLevel, DefaultTransactionDefinition.PREFIX_ISOLATION) :
"(unknown)"));
}
}
// 验证事物只读属性
// 如果当前事物可写,但是已有的事物是只读,则抛出异常
if (!definition.isReadOnly()) {
if (TransactionSynchronizationManager.isCurrentTransactionReadOnly()) {
throw new IllegalTransactionStateException("Participating transaction with definition [" +
definition + "] is not marked as read-only but existing transaction is");
}
}
}
boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
// 创建事物
return prepareTransactionStatus(definition, transaction, false, newSynchronization, debugEnabled, null);
}
总结一下这个方法干了啥:
- 当前事务传播行为等于 PROPAGATION_NEVER,则报错
- 当前事务传播行为等于 PROPAGATION_NOT_SUPPORTED,则挂起事务,走没有事务的逻辑
- 当前事务传播行为等于 PROPAGATION_REQUIRES_NEW,则创建个新的,老事务挂起
- 当前事务传播行为等于 PROPAGATION_NESTED,则嵌套事务使用,保存点,也就是说回滚也是回滚本方法得到
- 剩下的就是使用当前事务
这其中有几个重要方法我们要拿出来分析分析:
1、挂起当前事务,记录当前事务状态,以便后续的恢复操作
org.springframework.transaction.support.AbstractPlatformTransactionManager#suspend
protected final SuspendedResourcesHolder suspend(@Nullable Object transaction) throws TransactionException {
// 1.如果存在事物同步回调接口
if (TransactionSynchronizationManager.isSynchronizationActive()) {
// 1.1 挂起事务同步回调接口
List<TransactionSynchronization> suspendedSynchronizations = doSuspendSynchronization();
try {
// 挂起事物
Object suspendedResources = null;
if (transaction != null) {
suspendedResources = doSuspend(transaction);
}
// 获取已有事物名称
String name = TransactionSynchronizationManager.getCurrentTransactionName();
// 清空已有事物名称
TransactionSynchronizationManager.setCurrentTransactionName(null);
// 获取已有事物的readOnly属性值
boolean readOnly = TransactionSynchronizationManager.isCurrentTransactionReadOnly();
// 将已有事物的readOnly属性值设置为false
TransactionSynchronizationManager.setCurrentTransactionReadOnly(false);
// 获取已有事物数据库事物隔离级别
Integer isolationLevel = TransactionSynchronizationManager.getCurrentTransactionIsolationLevel();
// 清空已有事物数据库事物隔离级别
TransactionSynchronizationManager.setCurrentTransactionIsolationLevel(null);
// 获取已有事物激活标识
boolean wasActive = TransactionSynchronizationManager.isActualTransactionActive();
// 将当前事物激活标识设置为false
TransactionSynchronizationManager.setActualTransactionActive(false);
// 将上面获取到的一系列事物属性,重新封装至SuspendedResourcesHolder对象,并返回
return new SuspendedResourcesHolder(
suspendedResources, suspendedSynchronizations, name, readOnly, isolationLevel, wasActive);
}
catch (RuntimeException | Error ex) {
// doSuspend failed - original transaction is still active...
doResumeSynchronization(suspendedSynchronizations);
throw ex;
}
}
// 不存在事物同步回调接口,且当前事物不为空
else if (transaction != null) {
// Transaction active but no synchronization active.
// 事物已经被激活,但是没有事物同步回调,则直接挂起当前事物即可
Object suspendedResources = doSuspend(transaction);
// 返回挂起的事物资源
return new SuspendedResourcesHolder(suspendedResources);
}
// 处理没有事物的情况...
else {
// Neither transaction nor synchronization active.
return null;
}
}
2、新建事务
org.springframework.jdbc.datasource.DataSourceTransactionManager#doBegin
protected void doBegin(Object transaction, TransactionDefinition definition) {
DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
Connection con = null;
try {
if (!txObject.hasConnectionHolder() ||
txObject.getConnectionHolder().isSynchronizedWithTransaction()) {
// 从DataSource里获取一个连接(这个DataSource一般是有连接池的)
Connection newCon = obtainDataSource().getConnection();
if (logger.isDebugEnabled()) {
logger.debug("Acquired Connection [" + newCon + "] for JDBC transaction");
}
// 把这个链接用ConnectionHolder包装一下
txObject.setConnectionHolder(new ConnectionHolder(newCon), true);
}
txObject.getConnectionHolder().setSynchronizedWithTransaction(true);
con = txObject.getConnectionHolder().getConnection();
// 设置isReadOnly、设置隔离界别等
Integer previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(con, definition);
txObject.setPreviousIsolationLevel(previousIsolationLevel);
// Switch to manual commit if necessary. This is very expensive in some JDBC drivers,
// so we don't want to do it unnecessarily (for example if we've explicitly
// configured the connection pool to set it already).
// 这里非常的关键,先看看Connection 是否是自动提交的
// 如果是 就con.setAutoCommit(false) 要不然数据库默认没执行一条SQL都是一个事务,就没法进行事务的管理了
if (con.getAutoCommit()) {
txObject.setMustRestoreAutoCommit(true);
if (logger.isDebugEnabled()) {
logger.debug("Switching JDBC Connection [" + con + "] to manual commit");
}
//开启事务,设置autoCommit为false
con.setAutoCommit(false);
}
// ====因此从这后面,通过此Connection执行的所有SQL语句只要没有commit就都不会提交给数据库的=====
// 这个方法特别特别有意思 它自己`Statement stmt = con.createStatement()`拿到一个Statement
// 然后执行了一句SQL:`stmt.executeUpdate("SET TRANSACTION READ ONLY");`
// 所以:如果你仅仅只是查询。把事务的属性设置为readonly=true Spring对帮你对SQl进行优化的
// 需要注意的是:readonly=true 后,只能读,不能进行dml操作)
// (只能看到设置事物前数据的变化,看不到设置事物后数据的改变)
prepareTransactionalConnection(con, definition);
txObject.getConnectionHolder().setTransactionActive(true);
int timeout = determineTimeout(definition);
if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) {
txObject.getConnectionHolder().setTimeoutInSeconds(timeout);
}
// Bind the connection holder to the thread.
// 这一步:就是把当前的链接 和当前的线程进行绑定
if (txObject.isNewConnectionHolder()) {
//这里将当前的connection放入TransactionSynchronizationManager中持有,如果下次调用可以判断为已有的事务
TransactionSynchronizationManager.bindResource(obtainDataSource(), txObject.getConnectionHolder());
}
}
catch (Throwable ex) {
// 如果是新创建的链接,那就释放
if (txObject.isNewConnectionHolder()) {
DataSourceUtils.releaseConnection(con, obtainDataSource());
txObject.setConnectionHolder(null, false);
}
throw new CannotCreateTransactionException("Could not open JDBC Connection for transaction", ex);
}
}
总结该方法干了些啥:
- 尝试获取连接
- 设置隔离级别及只读标识
- 更改默认的提交设置
- 设置标志位,标识当前连接已经被事务激活
- 设置过期时间
- 将 connectionHolder 绑定到当前线程
最后,我们回到 getTransaction 方法,当不存在事务时,则执行流程与 handleExistingTransaction 方法的后半段类似。
下面我们再次回到 createTransactionIfNecessary 来看看 prepareTransactionInfo 方法,准备事务信息。
org.springframework.transaction.interceptor.TransactionAspectSupport#prepareTransactionInfo
protected TransactionInfo prepareTransactionInfo(@Nullable PlatformTransactionManager tm,
@Nullable TransactionAttribute txAttr, String joinpointIdentification,
@Nullable TransactionStatus status) {
// 构造一个TransactionInfo
TransactionInfo txInfo = new TransactionInfo(tm, txAttr, joinpointIdentification);
if (txAttr != null) {
// We need a transaction for this method...
if (logger.isTraceEnabled()) {
logger.trace("Getting transaction for [" + txInfo.getJoinpointIdentification() + "]");
}
// The transaction manager will flag an error if an incompatible tx already exists.
// 如果已存在不兼容的Tx,设置status
txInfo.newTransactionStatus(status);
}
else {
// The TransactionInfo.hasTransaction() method will return false. We created it only
// to preserve the integrity of the ThreadLocal stack maintained in this class.
if (logger.isTraceEnabled())
logger.trace("Don't need to create transaction for [" + joinpointIdentification +
"]: This method isn't transactional.");
}
// We always bind the TransactionInfo to the thread, even if we didn't create
// a new transaction here. This guarantees that the TransactionInfo stack
// will be managed correctly even if no transaction was created by this aspect.
// 这句话是最重要的:把生成的TransactionInfo并绑定到当前线程的ThreadLocal
txInfo.bindToThread();
return txInfo;
}
该方法创建一个 TransactionInfo 类型对象,它记录了事务的所有信息。当事务执行失败或成功时,会从这里获取相关信息执行对应逻辑。
3.2 目标方法执行
retVal = invocation.proceedWithInvocation();
这个代码可以理解就是去执行我们的业务方法,其内部是调用 AOP 的执行链,进而会调用 ReflectiveMethodInvocation#proceed 方法。
3.3 异常情况(提交或回滚事务)
completeTransactionAfterThrowing(txInfo, ex);
如果执行业务方法出错,会进入这个方法判断是回滚还是提交事务。
org.springframework.transaction.interceptor.TransactionAspectSupport#completeTransactionAfterThrowing
protected void completeTransactionAfterThrowing(@Nullable TransactionInfo txInfo, Throwable ex) {
if (txInfo != null && txInfo.getTransactionStatus() != null) {
if (logger.isTraceEnabled()) {
logger.trace("Completing transaction for [" + txInfo.getJoinpointIdentification() +
"] after exception: " + ex);
}
if (txInfo.transactionAttribute != null && 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 | Error ex2) {
logger.error("Application exception overridden by rollback exception", ex);
throw ex2;
}
}
else {
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 | Error ex2) {
logger.error("Application exception overridden by commit exception", ex);
throw ex2;
}
}
}
}
该方法要注意的就是如果设置了回滚的异常类型,那么在回滚之前会判断报错类型是否是指定的回滚类型,如果是则回滚,否则提交事务。
3.4 提交事务
commitTransactionAfterReturning(txInfo);
方法源码
org.springframework.transaction.interceptor.TransactionAspectSupport#commitTransactionAfterReturning
protected void commitTransactionAfterReturning(@Nullable TransactionInfo txInfo) {
if (txInfo != null && txInfo.getTransactionStatus() != null) {
if (logger.isTraceEnabled()) {
logger.trace("Completing transaction for [" + txInfo.getJoinpointIdentification() + "]");
}
// 提交事务
txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());
}
}
这个方法很简单,就是提交事务,底层调用的也是 Connection 中的 commit() 方法。
最后在额外看看这个清除事务信息方法:
cleanupTransactionInfo(txInfo);
org.springframework.transaction.interceptor.TransactionAspectSupport#cleanupTransactionInfo
protected void cleanupTransactionInfo(@Nullable TransactionInfo txInfo) {
if (txInfo != null) {
// 清理当前线程事务信息,如果有挂起事务则将挂起事务设置到当前线程上
txInfo.restoreThreadLocalStatus();
}
}
因为当前事务执行完毕了,所以需要将当前线程上的事务信息清空调用,然后获取到挂起的线程,并将挂起的线程再次设置到当前线程上,如果没有挂起线程则设置 null。
最后,画图小能手上线,Spring事务执行流程图如下:
至此,我们的事务相关内容就分析完毕了,撒花、撒花!
好了,今天的内容到这里就结束了,我是 【J3】关注我,我们下期见
。
-
由于博主才疏学浅,难免会有纰漏,假如你发现了错误或偏见的地方,还望留言给我指出来,我会对其加以修正。
-
如果你觉得文章还不错,你的转发、分享、点赞、留言就是对我最大的鼓励。
-
感谢您的阅读,十分欢迎并感谢您的关注。