一文学习 Spring 声明式事务源码全流程总结
Spring 声明式事务源码学习全过程
in short 四步走
- Srping 如何从配置中加载的入口
- Spring 声明式事务的相关的 BeanDefinition加载流程
- Spring 声明式事务的相关对象创建流程
- Spring 声明式事务的拦截调用的过程(包括: 方法嵌套, 事务传播属性的处理过程)
最后再看看第三方的框架是如何支持 Spring 声明式事务, 给Spring 托管事务的
一、Spring 声明式事务的入口点
对于XML入口点
XML配置定义
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx
https://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd">
<tx:annotation-driven></tx:annotation-driven>
<!-- dao bean-->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate" >
<property name="dataSource" ref = "dataSource"></property>
</bean>
<!-- service bean-->
<bean id="bookService" class="org.yang.learn.spring.tx.BookService" >
<property name="jdbcTemplate" ref="jdbcTemplate"></property>
</bean>
<!-- 数据源 bean-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" >
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver"></property>
<property name="url"
value="jdbc:mysql://192.168.40.171:3306/workflow_test?serverTimezone=Asia/Shanghai&characterEncoding=utf8&useSSL=false"/>
<property name="username" value="user_dev"></property>
<property name="password" value="dev-sny.com"></property>
</bean>
<!-- 事务管理bean-->
<bean id="transactionManager" class="org.springframework.jdbc.support.JdbcTransactionManager" >
<constructor-arg ref="dataSource"></constructor-arg>
</bean>
<aop:config>
<!--切点配置 -->
<aop:pointcut id="serviceOperation"
expression="execution(* org.yang.learn.spring.tx.BookService.*(..))"/>
<!-- 通知/增强 配置 (关键是这个通知指向 txAdvice '事务增强')-->
<aop:advisor pointcut-ref="serviceOperation" advice-ref="txAdvice"/>
</aop:config>
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="get*" read-only="true"/>
<tx:method name="insertWithTransaction" propagation="REQUIRED" />
<tx:method name="insertWithNoTransaction" propagation="NEVER" />
</tx:attributes>
</tx:advice>
</beans>
在XML中配置 tx:.. 启用tx标签, 在解析XML自定义标签时, 会拿到 TxNamespaceHandler 命名空间处理器, 其主要工作就是注册事务相关的标签的解析器
- tx:advice 标签解析器:负责XML相关的标签解析
TxAdviceBeanDefinitionParser - tx:annotation-driven 标签解析器:负责注解相关的解析
AnnotationDrivenBeanDefinitionPar
org.springframework.transaction.config.TxNamespaceHandler
public class TxNamespaceHandler extends NamespaceHandlerSupport {
static final String TRANSACTION_MANAGER_ATTRIBUTE = "transaction-manager";
static final String DEFAULT_TRANSACTION_MANAGER_BEAN_NAME = "transactionManager";
static String getTransactionManagerName(Element element) {
return (element.hasAttribute(TRANSACTION_MANAGER_ATTRIBUTE) ?
element.getAttribute(TRANSACTION_MANAGER_ATTRIBUTE) : DEFAULT_TRANSACTION_MANAGER_BEAN_NAME);
}
@Override
public void init() {
// <tx:advice> 标签解析器:负责解析XML <tx:advice> 事务标签配置 TxAdviceBeanDefinitionParser
registerBeanDefinitionParser("advice", new TxAdviceBeanDefinitionParser());
// <tx:annotation-driven> 标签解析器:负责解析注解相关的事务配置 AnnotationDrivenBeanDefinitionParser
registerBeanDefinitionParser("annotation-driven", new AnnotationDrivenBeanDefinitionParser());
// JTA 规范的分布式事务管理器(管理跨多个资源的事务) TODO
registerBeanDefinitionParser("jta-transaction-manager", new JtaTransactionManagerBeanDefinitionParser());
}
}
启用事务注解支持
class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser {
/**
* Parses the {@code <tx:annotation-driven/>} tag. Will
* {@link AopNamespaceUtils#registerAutoProxyCreatorIfNecessary register an AutoProxyCreator}
* with the container as necessary.
*/
@Override
@Nullable
public BeanDefinition parse(Element element, ParserContext parserContext) {
registerTransactionalEventListenerFactory(parserContext);
String mode = element.getAttribute("mode");
if ("aspectj".equals(mode)) {
// mode="aspectj"
registerTransactionAspect(element, parserContext);
if (ClassUtils.isPresent("jakarta.transaction.Transactional", getClass().getClassLoader())) {
registerJtaTransactionAspect(element, parserContext);
}
}
else {
// 默认是 proxy 模式
// mode="proxy"
AopAutoProxyConfigurer.configureAutoProxyCreator(element, parserContext);
}
return null;
}
注册三剑客
/**
* Inner class to just introduce an AOP framework dependency when actually in proxy mode.
*/
private static class AopAutoProxyConfigurer {
public static void configureAutoProxyCreator(Element element, ParserContext parserContext) {
AopNamespaceUtils.registerAutoProxyCreatorIfNecessary(parserContext, element);
String txAdvisorBeanName = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME;
if (!parserContext.getRegistry().containsBeanDefinition(txAdvisorBeanName)) {
Object eleSource = parserContext.extractSource(element);
// Create the TransactionAttributeSource definition.
RootBeanDefinition sourceDef = new RootBeanDefinition(
"org.springframework.transaction.annotation.AnnotationTransactionAttributeSource");
sourceDef.setSource(eleSource);
sourceDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
String sourceName = parserContext.getReaderContext().registerWithGeneratedName(sourceDef);
// Create the TransactionInterceptor definition.
RootBeanDefinition interceptorDef = new RootBeanDefinition(TransactionInterceptor.class);
interceptorDef.setSource(eleSource);
interceptorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
registerTransactionManager(element, interceptorDef);
interceptorDef.getPropertyValues().add("transactionAttributeSource", new RuntimeBeanReference(sourceName));
String interceptorName = parserContext.getReaderContext().registerWithGeneratedName(interceptorDef);
/**
* 其中构建事务增强器(BeanFactoryTransactionAttributeSourceAdvisor)
* - **Pointcut(切点)**: 默认匹配所有标注 `@Transactional` 的类 / 方法(由 `TransactionAttributeSourcePointcut` 实现)
* - **Advice(通知)**: 即 `TransactionInterceptor`(事务拦截器)
* - **TransactionAttributeSource(注解解析器)**:即 `AnnotationTransactionAttributeSource`, 负责解析 `@Transactional` 注解的属性(传播行为、隔离级别等)。
*/
// Create the TransactionAttributeSourceAdvisor definition.
RootBeanDefinition advisorDef = new RootBeanDefinition(BeanFactoryTransactionAttributeSourceAdvisor.class);
advisorDef.setSource(eleSource);
advisorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
advisorDef.getPropertyValues().add("transactionAttributeSource", new RuntimeBeanReference(sourceName));
advisorDef.getPropertyValues().add("adviceBeanName", interceptorName);
if (element.hasAttribute("order")) {
advisorDef.getPropertyValues().add("order", element.getAttribute("order"));
}
parserContext.getRegistry().registerBeanDefinition(txAdvisorBeanName, advisorDef);
CompositeComponentDefinition compositeDef = new CompositeComponentDefinition(element.getTagName(), eleSource);
compositeDef.addNestedComponent(new BeanComponentDefinition(sourceDef, sourceName));
compositeDef.addNestedComponent(new BeanComponentDefinition(interceptorDef, interceptorName));
compositeDef.addNestedComponent(new BeanComponentDefinition(advisorDef, txAdvisorBeanName));
parserContext.registerComponent(compositeDef);
}
}
}
事务注解支持的三剑客
- AnnotationTransactionAttributeSource
↓(解析注解) - TransactionInterceptor
↓(执行事务逻辑) - BeanFactoryTransactionAttributeSourceAdvisor
↓(组装切点+通知)
总结一下XML入口, 就是无论 xml 支持 还是注解支持都会构造 org.springframework.transaction.interceptor.TransactionInterceptor 这个核心 advice 事务拦截器
对于注解的入口
@EnableTransactionManagement
public class TXMain {
@Transactional
public static void main(String[] args) throws Exception {
System.out.println("==========================================================");
//ApplicationContext context = new ClassPathXmlApplicationContext("application-tx.xml");
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(TXMain.class);
BookService bookService = context.getBean("bookService", BookService.class);
Book book = new Book();
book.setName("30秒精通javascript,一分钟精通java");
book.setCode(""+System.currentTimeMillis());
// bookService.insertWithTransaction(book );
bookService.insertWithNoTransaction(book);
System.out.println("bookService = "+bookService);
System.out.println("bookService getList = "+bookService.getList());
System.out.println("==========================================================");
}
}
@EnableTransactionManagement 注解导入了 TransactionManagementConfigurationSelector 默认选中的是 ProxyTransactionManagementConfiguration
public class TransactionManagementConfigurationSelector extends AdviceModeImportSelector<EnableTransactionManagement> {
/**
* Returns {@link ProxyTransactionManagementConfiguration} or
* {@code AspectJ(Jta)TransactionManagementConfiguration} for {@code PROXY}
* and {@code ASPECTJ} values of {@link EnableTransactionManagement#mode()},
* respectively.
*/
@Override
protected String[] selectImports(AdviceMode adviceMode) {
return switch (adviceMode) {
case PROXY -> new String[] {AutoProxyRegistrar.class.getName(),
ProxyTransactionManagementConfiguration.class.getName()};
case ASPECTJ -> new String[] {determineTransactionAspectClass()};
};
}
private String determineTransactionAspectClass() {
return (ClassUtils.isPresent("jakarta.transaction.Transactional", getClass().getClassLoader()) ?
TransactionManagementConfigUtils.JTA_TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME :
TransactionManagementConfigUtils.TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME);
}
}
同样注解的三剑客
- AnnotationTransactionAttributeSource
↓(解析注解) - TransactionInterceptor
↓(执行事务逻辑) - BeanFactoryTransactionAttributeSourceAdvisor
↓(组装切点+通知)
org.springframework.transaction.annotation.ProxyTransactionManagementConfiguration
/*
* Copyright 2002-2021 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
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.ImportRuntimeHints;
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
* @author Sebastien Deleuze
* @since 3.1
* @see EnableTransactionManagement
* @see TransactionManagementConfigurationSelector
*/
@Configuration(proxyBeanMethods = false)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
@ImportRuntimeHints(TransactionRuntimeHints.class)
public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {
@Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor(
TransactionAttributeSource transactionAttributeSource, TransactionInterceptor transactionInterceptor) {
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() {
// Accept protected @Transactional methods on CGLIB proxies, as of 6.0.
return new AnnotationTransactionAttributeSource(false);
}
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public TransactionInterceptor transactionInterceptor(TransactionAttributeSource transactionAttributeSource) {
TransactionInterceptor interceptor = new TransactionInterceptor();
interceptor.setTransactionAttributeSource(transactionAttributeSource);
if (this.txManager != null) {
interceptor.setTransactionManager(this.txManager);
}
return interceptor;
}
}
总结流程图

二、事务相关的 BeanDefinition 解析过程 (XML)
bean 标签
对于 jdbcTemplate transactionManager dataSource bookService 走的是默认命名空间的处理器, IOC标准解析流程, 不再啰嗦了
[[Spring IOC 源码学习 XML详细加载流程总结]]
org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader#parseBeanDefinitions
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
if (delegate.isDefaultNamespace(root)) {
NodeList nl = root.getChildNodes();
for (int i = 0; i < nl.getLength(); i++) {
Node node = nl.item(i);
if (node instanceof Element ele) {//是否 是元素标签
/**
* 处理默认命名空间的标签, 有如下四个
* <import></import>, <alias> </alias>, <bean></bean>, <beans></beans>
*
*/
if (delegate.isDefaultNamespace(ele)) {
parseDefaultElement(ele, delegate);
}
else {
/**
* 处理 非默认命名空间的标签;
* 注意这里包括 <context:bean ...> <aop:xx ...> <tx:xx ...> 等等所有指定命名空间的xml配置
* 主要逻辑是: 拿到元素的命名空间URI, 再从 XmlReaderContext 找到对应的 NamespaceHandler 调用解析 `parse`方法解析到 BeanDefinition 返回
*/
delegate.parseCustomElement(ele);
}
}
}
}
else {
delegate.parseCustomElement(root);
}
}
aop 标签
对于 aop 部分的标签则的是 AOP 的流程
<aop:config>
<!--切点配置 -->
<aop:pointcut id="serviceOperation"
expression="execution(* org.yang.learn.spring.tx.BookService.*(..))"/>
<!-- 通知/增强 配置 (关键是这个通知指向 txAdvice '事务增强')-->
<aop:advisor pointcut-ref="serviceOperation" advice-ref="txAdvice"/>
</aop:config>
<aop:pointcut...: 解析为 org.springframework.aop.aspectj.AspectJExpressionPointcut 其 BeanDefinition<aop:advisor...: 解析为 org.springframework.aop.support.DefaultBeanFactoryPointcutAdvisor 其 BeanDefinition
internalAutoProxyCreator 的注册
[[Spring AOP 源码学习 详细流程总结]]
这里要注意AOP 的 ConfigBeanDefinitionParser 在解析时是会注册的一个internalAutoProxyCreator! (AOP解析流程, 在BPP回调时创建代理对象的)
org.springframework.aop.config.ConfigBeanDefinitionParser#parse
@Override
@Nullable
public BeanDefinition parse(Element element, ParserContext parserContext) {
CompositeComponentDefinition compositeDef =
new CompositeComponentDefinition(element.getTagName(), parserContext.extractSource(element));
parserContext.pushContainingComponent(compositeDef);
/**
* 1. 注册一个名称为`org.springframework.aop.config.internalAutoProxyCreator` 对AOP处理的Bean Definition; 它是实现 InstantiationAwareBeanPostProcessor 接口的
* 名称是: org.springframework.aop.config.internalAutoProxyCreator
* 对应的类, 根据情况有以下三个可能: org.springframework.aop.config.AopConfigUtils#APC_PRIORITY_LIST
* InfrastructureAdvisorAutoProxyCreator.class,AspectJAwareAdvisorAutoProxyCreator.class, AnnotationAwareAspectJAutoProxyCreator.class
* 注册一个名称为`org.springframework.aop.config.internalAutoProxyCreator` 对AOP处理的Bean Definition; 它是实现 InstantiationAwareBeanPostProcessor 接口的
*
*/
configureAutoProxyCreator(parserContext, element);
解析 <aop:pointcut>, <aop:advisor>, 没有切面标签
org.springframework.aop.config.ConfigBeanDefinitionParser#parse
@Override
@Nullable
public BeanDefinition parse(Element element, ParserContext parserContext) {
CompositeComponentDefinition compositeDef =
new CompositeComponentDefinition(element.getTagName(), parserContext.extractSource(element));
parserContext.pushContainingComponent(compositeDef);
/**
* 1. 注册一个名称为`org.springframework.aop.config.internalAutoProxyCreator` 对AOP处理的Bean Definition; 它是实现 InstantiationAwareBeanPostProcessor 接口的
* 名称是: org.springframework.aop.config.internalAutoProxyCreator
* 对应的类, 根据情况有以下三个可能: org.springframework.aop.config.AopConfigUtils#APC_PRIORITY_LIST
* InfrastructureAdvisorAutoProxyCreator.class,AspectJAwareAdvisorAutoProxyCreator.class, AnnotationAwareAspectJAutoProxyCreator.class
* 注册一个名称为`org.springframework.aop.config.internalAutoProxyCreator` 对AOP处理的Bean Definition; 它是实现 InstantiationAwareBeanPostProcessor 接口的
*
*/
configureAutoProxyCreator(parserContext, element);
/**
* 2. 解析 <aop:config> 标签的子元素 (pointcut, advisor, aspect)
* 解析 <aspect ...>:
* 每一个通知(Advice) 都会封装为一个 AspectJPointcutAdvisor 的BeanDefinition 然后将其注册到 BeanFactory
*
* AspectJPointcutAdvisor 的包含情况
* 每一个通知(Advice) 都会封装为一个 AspectJPointcutAdvisor(通知器) 类型的BeanDefinition 然后将其注册到 BeanFactory
* AspectJPointcutAdvisor 内部包含五种通知类类型: AspectJAfterReturningAdvice AspectJAfterAdvice AspectJAroundAdvice AspectJMethodBeforeAdvice AspectJAfterThrowingAdvice
* 而每种通知类型的内部又主要有三个关键属性,包括:
* 1. java.lang.reflect.Method(通知切面的方法)
* 2. org.springframework.aop.aspectj.AspectJExpressionPointcut(切入点表达式)
* 3. org.springframework.aop.aspectj.AspectInstanceFactory (切面实例工厂)
*/
List<Element> childElts = DomUtils.getChildElements(element);
for (Element elt: childElts) {
String localName = parserContext.getDelegate().getLocalName(elt);
switch (localName) {
/**
* 解析 pointcut/切入点 //筛选连接点, 即: 哪些方法需要被代理
* 解析为 org.springframework.aop.aspectj.AspectJExpressionPointcut 注册其 BeanDefinition
*/
case POINTCUT -> parsePointcut(elt, parserContext);
/**
* 解析 advisor/通知/建议/增强处理 //即: 增强功能这一部分代码
* 解析为 org.springframework.aop.support.DefaultBeanFactoryPointcutAdvisor 注册其 BeanDefinition
*/
case ADVISOR -> parseAdvisor(elt, parserContext);
/**
*/
case ASPECT -> parseAspect(elt, parserContext);
}
}
parserContext.popAndRegisterContainingComponent();
return null;
}
tx 标签
前文说了由 org.springframework.transaction.config.TxAdviceBeanDefinitionParser 负责XML解析
先来到父类方法解析 TransactionInterceptor
org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser#parseInternal
/**
* Creates a {@link BeanDefinitionBuilder} instance for the
* {@link #getBeanClass bean Class} and passes it to the
* {@link #doParse} strategy method.
* @param element the element that is to be parsed into a single BeanDefinition
* @param parserContext the object encapsulating the current state of the parsing process
* @return the BeanDefinition resulting from the parsing of the supplied {@link Element}
* @throws IllegalStateException if the bean {@link Class} returned from
* {@link #getBeanClass(org.w3c.dom.Element)} is {@code null}
* @see #doParse
*
*/
@Override
protected final AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) {
/**
*
* 1. 解析 <tx:advice ... 标签 封装为`GenericBeanDefinition`
* 其名称和class为org.springframework.transaction.interceptor.TransactionInterceptor
* 注意这个 TransactionInterceptor 实现了MethodInterceptor相当于是个Advice
*
* org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser
* #parseInternal(org.w3c.dom.Element, org.springframework.beans.factory.xml.ParserContext)
* org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser#parseInternal
*
*
*/
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition();
String parentName = getParentName(element);
if (parentName != null) {
builder.getRawBeanDefinition().setParentName(parentName);
}
Class<?> beanClass = getBeanClass(element);
if (beanClass != null) {
builder.getRawBeanDefinition().setBeanClass(beanClass);
}
else {
String beanClassName = getBeanClassName(element);
if (beanClassName != null) {
builder.getRawBeanDefinition().setBeanClassName(beanClassName);
}
}
builder.getRawBeanDefinition().setSource(parserContext.extractSource(element));
BeanDefinition containingBd = parserContext.getContainingBeanDefinition();
if (containingBd != null) {
// Inner bean definition must receive same scope as containing bean.
builder.setScope(containingBd.getScope());
}
if (parserContext.isDefaultLazyInit()) {
// Default-lazy-init applies to custom bean definitions as well.
builder.setLazyInit(true);
}
doParse(element, parserContext, builder);
return builder.getBeanDefinition();
}
在回来解析到 transactionAttributeSource
org.springframework.transaction.config.TxAdviceBeanDefinitionParser#doParse
@Override
protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
/**
* 添加 transactionManager (事务管理)的 ref
*/
builder.addPropertyReference("transactionManager", TxNamespaceHandler.getTransactionManagerName(element));
List<Element> txAttributes = DomUtils.getChildElementsByTagName(element, ATTRIBUTES_ELEMENT);
if (txAttributes.size() > 1) {
parserContext.getReaderContext().error(
"Element <attributes> is allowed at most once inside element <advice>", element);
}
else if (txAttributes.size() == 1) {
/**
* 解析 <tx:attributes> ... 子标签
* 包括: 匹配的目标方法, 事务的传播属性, 是否只读..
* 类型是 `org.springframework.transaction.interceptor.NameMatchTransactionAttributeSource`
*/
// Using attributes source.
Element attributeSourceElement = txAttributes.get(0);
RootBeanDefinition attributeSourceDefinition = parseAttributeSource(attributeSourceElement, parserContext);
builder.addPropertyValue("transactionAttributeSource", attributeSourceDefinition);
}
else {
// Assume annotations source.
builder.addPropertyValue("transactionAttributeSource",
new RootBeanDefinition("org.springframework.transaction.annotation.AnnotationTransactionAttributeSource"));
}
}
汇总图

事务相关对象的BeanDefinition 对应AOP的三剑客
首先一点事务增强, 本质上就是AOP的逻辑, 在AOP最重要的就是AspectJPointcutAdvisor包含的三剑客

对应关系

可以看到少了AspectInstanceFactory 在事务这里的逻辑中不需它; 因为切面的逻辑是硬编码在TransactionInterceptor中了;
至此在事务相关的AOP对象已经齐了
三、事务增强 相关的对象创建
internalAutoProxyCreator 对象
首先是 internalAutoProxyCreator 它是负责创建AOP对象 它本身是BPP, 它会在 registerBeanPostProcessors(beanFactory); 过程中被实例化
org.springframework.context.support.PostProcessorRegistrationDelegate#registerBeanPostProcessors(org.springframework.beans.factory.config.ConfigurableListableBeanFactory, org.springframework.context.support.AbstractApplicationContext)
/**
* in short:
* 1. 拿到所有实现 BeanPostProcessor 的 bean, 然后进行分类存起来
* 这有一点, Spring 对 BeanDefinition 分成三种角色:
* 1. 用户定义的 Bean (ROLE_APPLICATION)
* 2. 较复杂的 (ROLE_SUPPORT) 较复杂的? 通常是一个外部配置
* 3. Spring 内置的(ROLE_INFRASTRUCTURE)
* 2. 如果实现了 BeanPostProcessor 则会实例化这个bean, 但注意这里只是注册,并不会调用BeanPostProcessor的相关方法
*
* 另外 BeanPostProcessor 粗粒度太大, Spring 还细分一些子接口:
* - SmartInstantiationAwareBeanPostProcessor 它提供了更高级的Bean实例化控制方法。主要作用在于允许对Bean的实例化过程进行更精细的控制和定制。
* - MergedBeanDefinitionPostProcessor 在合并Bean定义(MergedBeanDefinition)之后但在实例化Bean之前,允许对合并后的Bean定义进行修改、调整或附加元数据。
* - DestructionAwareBeanPostProcessor 它允许在Bean被销毁之前(例如,容器关闭或特定作用域的Bean销毁)执行一些操作。
*/
public static void registerBeanPostProcessors(
ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) {
// WARNING: Although it may appear that the body of this method can be easily
// refactored to avoid the use of multiple loops and multiple lists, the use
// of multiple lists and multiple passes over the names of processors is
// intentional. We must ensure that we honor the contracts for PriorityOrdered
// and Ordered processors. Specifically, we must NOT cause processors to be
// instantiated (via getBean() invocations) or registered in the ApplicationContext
// in the wrong order.
//
// Before submitting a pull request (PR) to change this method, please review the
// list of all declined PRs involving changes to PostProcessorRegistrationDelegate
// to ensure that your proposal does not result in a breaking change:
// https://github.com/spring-projects/spring-framework/issues?q=PostProcessorRegistrationDelegate+is%3Aclosed+label%3A%22status%3A+declined%22
/**
* 拿到所有实现 BeanPostProcessor 的 bean名称
*/
String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);
// Register BeanPostProcessorChecker that logs an info message when
// a bean is created during BeanPostProcessor instantiation, i.e. when
// a bean is not eligible for getting processed by all BeanPostProcessors.
/**
* 计算 BeanPostProcessor(BPP) 的总数.
* +1 是什么操作? 原因是: 下一行,又加了一个 BeanPostProcessorChecker
*/
int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 + postProcessorNames.length;
// BeanPostProcessorChecker 这个BeanPostProcessor, 没啥实际作用, 就是记录了一些日志;
beanFactory.addBeanPostProcessor(
new BeanPostProcessorChecker(beanFactory, postProcessorNames, beanProcessorTargetCount));
// Separate between BeanPostProcessors that implement PriorityOrdered,
// Ordered, and the rest.
/**
* 对 BeanPostProcessor 进行分类存起来, 再调用, 每个集合分别是
* 1. priorityOrderedPostProcessors //有实现(PriorityOrdered)排序接口的
* 2. internalPostProcessors //Spring内部的bean, 见: Spring将bean分为三种角色
* 3. orderedPostProcessorNames //实现 Ordered 接口
* 4. nonOrderedPostProcessorNames //没有指定顺序, 无序的
*/
List<BeanPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
List<BeanPostProcessor> internalPostProcessors = new ArrayList<>();
List<String> orderedPostProcessorNames = new ArrayList<>();
List<String> nonOrderedPostProcessorNames = new ArrayList<>();
for (String ppName : postProcessorNames) {
if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
/**
* 注意, 若 bean 实现了 PriorityOrdered 接口, 则会优先实例化它;
*/
BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
priorityOrderedPostProcessors.add(pp);
if (pp instanceof MergedBeanDefinitionPostProcessor) {
internalPostProcessors.add(pp);
}
}
else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
orderedPostProcessorNames.add(ppName);
}
else {
nonOrderedPostProcessorNames.add(ppName);
}
}
// First, register the BeanPostProcessors that implement PriorityOrdered.
sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors);
// Next, register the BeanPostProcessors that implement Ordered.
List<BeanPostProcessor> orderedPostProcessors = new ArrayList<>(orderedPostProcessorNames.size());
for (String ppName : orderedPostProcessorNames) {
BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
orderedPostProcessors.add(pp);
if (pp instanceof MergedBeanDefinitionPostProcessor) {
internalPostProcessors.add(pp);
}
}
sortPostProcessors(orderedPostProcessors, beanFactory);
registerBeanPostProcessors(beanFactory, orderedPostProcessors);
/**
* 注册所有常规BeanPostProcessors
* 这里 getBean 实例化bean !;
*/
// Now, register all regular(常规) BeanPostProcessors.
List<BeanPostProcessor> nonOrderedPostProcessors = new ArrayList<>(nonOrderedPostProcessorNames.size());
for (String ppName : nonOrderedPostProcessorNames) {
BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
nonOrderedPostProcessors.add(pp);
if (pp instanceof MergedBeanDefinitionPostProcessor) {
internalPostProcessors.add(pp);
}
}
registerBeanPostProcessors(beanFactory, nonOrderedPostProcessors);
/**
* 最后, 注册所有 内置 BeanPostProcessor
*/
// Finally, re-register all internal BeanPostProcessors.
sortPostProcessors(internalPostProcessors, beanFactory);
registerBeanPostProcessors(beanFactory, internalPostProcessors);
//最后再放一个 ApplicationListenerDetector 让它在最后 (不是重点, 见名应该是事件相关的)
// Re-register post-processor for detecting inner beans as ApplicationListeners,
// moving it to the end of the processor chain (for picking up proxies etc).
beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(applicationContext));
}
DefaultBeanFactoryPointcutAdvisor 和 AspectJExpressionPointcut 对象
internalAutoProxyCreator 会在 postProcessBeforeInstantiation 回调中的org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#shouldSkip判断时实例化所有的 Advisor
在实例化 Advisor 填充属性时也会把 AspectJExpressionPointcut 也实例化
org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#postProcessBeforeInstantiation
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {
/**
* 常规情况下: 这里只是检查下缓存和标记缓存
* 对于真正的AOP代理创建见:
* {@link AbstractAutoProxyCreator#postProcessAfterInitialization(java.lang.Object, java.lang.String)}
*/
Object cacheKey = getCacheKey(beanClass, beanName);
if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {
/**
*
* 不管需不需要, 只要处理过了就缓存
* advisedBeans 这个变量, 缓存所有处理过的 bean名称;
* value 为 boolean值, 如果为false 则不处理
*/
if (this.advisedBeans.containsKey(cacheKey)) {
return null;
}
/**
* isInfrastructureClass 是否是基础功能类,即 AOP相关的几个类:
* Advice.class Pointcut.class Advisor.class AopInfrastructureBean.class 都为true
*
* shouldSkip 判断时, 拿到容器的所有 Advisor, 并且实例化 `getBean()` 这个 Advisor
*/
if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return null;
}
}
// Create proxy here if we have a custom TargetSource.
// Suppresses unnecessary default instantiation of the target bean:
// The TargetSource will handle target instances in a custom fashion.
TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
if (targetSource != null) {
if (StringUtils.hasLength(beanName)) {
this.targetSourcedBeans.add(beanName);
}
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}
return null;
}
TransactionInterceptort 对象
是在 internalAutoProxyCreator 遇到需要增强代理的对象时, 这里是 bookService 去 getAdvicesAndAdvisorsForBean 查找到其匹配 bookService 的 Advisor
这里若 Advisor 匹配, 会调用 getAdvice 获取其切面, 此时切面不存在则会实例化它
org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#wrapIfNecessary
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
return bean;
}
if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
return bean;
}
if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
/**
* 拿到所有匹配织入当前bean的 所有通知器(Advisor)
* 做了三件事, 见: {@link org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator#getAdvicesAndAdvisorsForBean(java.lang.Class, java.lang.String, org.springframework.aop.TargetSource)}
* 1. 往返回 `AspectJXXXAdvice`列表数组`0`索引 插入一个{@link org.springframework.aop.interceptor.ExposeInvocationInterceptor} 实例
* 方便传递参数用的
*
* 2. 怎么匹配(Advisor)?
* Advisor中的 `AspectJExpressionPointcut` 是实现 {@link ClassFilter} 和 {@link org.springframework.aop.MethodMatcher} 接口
* 一个进行类匹配, 一个进行方法匹配. Advisor 匹配会调用 getAdvice 获取其切面, 此时切面不存在则会实例化
*
* 3. 排序, 基于 `有向无环` 图进行排序; 可能匹配到多个切面(aspect)
*
*/
// Create proxy if we have advice.
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
if (specificInterceptors != DO_NOT_PROXY) {
/**
*{@link org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#advisedBeans}
* 这个变量缓存所有处理过的 bean名称, value 为 boolean值, 如果为false 则不处理
*/
this.advisedBeans.put(cacheKey, Boolean.TRUE);//缓存, 表示已处理
/**
* 创建代理
*
*/
Object proxy = createProxy(
bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
汇总图

四、事务增强 相关的方法调用流程
对于嵌套事务关键两个对象
首先梳理一下, 这里最复杂的问题是有多层方法嵌套的事务时, 对于事务的传播特性, 应该如何处理?
因为整个处理流程中涉及的对象非常多, 对于理解这里面的逻辑最为关键的对象有两个 TransactionStatus 和 TransactionInfo
TransactionInfo
该对象是在事务多层嵌套时流转的核心对象, 它几乎持有事务相关的所有对象
org.springframework.transaction.interceptor.TransactionAspectSupport.TransactionInfo
/**
* Opaque object used to hold transaction information. Subclasses
* must pass it back to methods on this class, but not see its internals.
*/
protected static final class TransactionInfo {
// 1. 事务管理器(DataSource/JPA等事务管理器)
private final PlatformTransactionManager transactionManager;
// 2. 事务属性(传播行为、隔离级别、超时、只读等)
private final TransactionAttribute transactionAttribute;
// 3. 切入的目标方法名(用于日志、异常追踪)
private final String joinpointIdentification;
// 4. 真实的事务状态(Spring 事务核心状态对象)
private TransactionStatus transactionStatus;
// 5. 上一个事务信息(处理事务嵌套/挂起,形成链表)
private TransactionInfo previousTransactionInfo;
@Nullable
private TransactionInfo oldTransactionInfo;
public TransactionInfo(@Nullable PlatformTransactionManager transactionManager,
@Nullable TransactionAttribute transactionAttribute, String joinpointIdentification) {
this.transactionManager = transactionManager;
this.transactionAttribute = transactionAttribute;
this.joinpointIdentification = joinpointIdentification;
}
public PlatformTransactionManager getTransactionManager() {
Assert.state(this.transactionManager != null, "No PlatformTransactionManager set");
return this.transactionManager;
}
@Nullable
public TransactionAttribute getTransactionAttribute() {
return this.transactionAttribute;
}
/**
* Return a String representation of this joinpoint (usually a Method call)
* for use in logging.
*/
public String getJoinpointIdentification() {
return this.joinpointIdentification;
}
public void newTransactionStatus(@Nullable TransactionStatus status) {
this.transactionStatus = status;
}
@Nullable
public TransactionStatus getTransactionStatus() {
return this.transactionStatus;
}
/**
* Return whether a transaction was created by this aspect,
* or whether we just have a placeholder to keep ThreadLocal stack integrity.
*/
public boolean hasTransaction() {
return (this.transactionStatus != null);
}
private void bindToThread() {
// Expose current TransactionStatus, preserving any existing TransactionStatus
// for restoration after this transaction is complete.
this.oldTransactionInfo = transactionInfoHolder.get();
transactionInfoHolder.set(this);
}
private void restoreThreadLocalStatus() {
// Use stack to restore old transaction TransactionInfo.
// Will be null if none was set.
transactionInfoHolder.set(this.oldTransactionInfo);
}
@Override
public String toString() {
return (this.transactionAttribute != null ? this.transactionAttribute.toString() : "No transaction");
}
}
// 1. 事务管理器(DataSource/JPA等事务管理器)
private final PlatformTransactionManager transactionManager;
// 2. 事务属性(传播行为、隔离级别、超时、只读等)
private final TransactionAttribute transactionAttribute;
// 3. 切入的目标方法名(用于日志、异常追踪)
private final String joinpointIdentification;
// 4. 真实的事务状态(Spring 事务核心状态对象)
private TransactionStatus transactionStatus;
// 5. 上一个事务信息(处理事务嵌套/挂起,形成链表)
private TransactionInfo previousTransactionInfo;
@Nullable
private TransactionInfo oldTransactionInfo;
记录了当前线程正在执行的事务所有关键信息,支撑事务的开启、挂起、恢复、提交 / 回滚全流程
对于这个状态对象关键的点是, 在多层嵌套时;
org.springframework.transaction.interceptor.TransactionAspectSupport#invokeWithinTransaction
- 在每次嵌套时都会调用
bindToThread
private void bindToThread() {
// Expose current TransactionStatus, preserving any existing TransactionStatus
// for restoration after this transaction is complete.
this.oldTransactionInfo = transactionInfoHolder.get();
transactionInfoHolder.set(this);
}
保存上一个 TransactionInfo
- 在嵌套方法结束返回是调用
restoreThreadLocalStatus
private void restoreThreadLocalStatus() {
// Use stack to restore old transaction TransactionInfo.
// Will be null if none was set.
transactionInfoHolder.set(this.oldTransactionInfo);
}
恢复上一个 TransactionInfo
TransactionStatus
org.springframework.transaction.TransactionStatus
public interface TransactionStatus extends TransactionExecution, SavepointManager, Flushable {
/**
* Return whether this transaction internally carries a savepoint,
* that is, has been created as nested transaction based on a savepoint.
* <p>This method is mainly here for diagnostic purposes, alongside
* {@link #isNewTransaction()}. For programmatic handling of custom
* savepoints, use the operations provided by {@link SavepointManager}.
* <p>The default implementation returns {@code false}.
* @see #isNewTransaction()
* @see #createSavepoint()
* @see #rollbackToSavepoint(Object)
* @see #releaseSavepoint(Object)
*/
default boolean hasSavepoint() {
return false;
}
/**
* Flush the underlying session to the datastore, if applicable:
* for example, all affected Hibernate/JPA sessions.
* <p>This is effectively just a hint and may be a no-op if the underlying
* transaction manager does not have a flush concept. A flush signal may
* get applied to the primary resource or to transaction synchronizations,
* depending on the underlying resource.
* <p>The default implementation is empty, considering flush as a no-op.
*/
@Override
default void flush() {
}
}
大部分属性其实都在它的父类 TransactionExecution
org.springframework.transaction.TransactionExecution
package org.springframework.transaction;
/**
* Common representation of the current state of a transaction.
* Serves as base interface for {@link TransactionStatus} as well as
* {@link ReactiveTransaction}, and as of 6.1 also as transaction
* representation for {@link TransactionExecutionListener}.
*
* @author Juergen Hoeller
* @since 5.2
*/
public interface TransactionExecution {
/**
* Return the defined name of the transaction (possibly an empty String).
* <p>In case of Spring's declarative transactions, the exposed name will be
* the {@code fully-qualified class name + "." + method name} (by default).
* <p>The default implementation returns an empty String.
* @since 6.1
* @see TransactionDefinition#getName()
*/
default String getTransactionName() {
return "";
}
/**
* Return whether there is an actual transaction active: this is meant to cover
* a new transaction as well as participation in an existing transaction, only
* returning {@code false} when not running in an actual transaction at all.
* <p>The default implementation returns {@code true}.
* @since 6.1
* @see #isNewTransaction()
* @see #isNested()
* @see #isReadOnly()
*/
default boolean hasTransaction() {
return true;
}
/**
* Return whether the transaction manager considers the present transaction
* as new; otherwise participating in an existing transaction, or potentially
* not running in an actual transaction in the first place.
* <p>This is primarily here for transaction manager state handling.
* Prefer the use of {@link #hasTransaction()} for application purposes
* since this is usually semantically appropriate.
* <p>The "new" status can be transaction manager specific, e.g. returning
* {@code true} for an actual nested transaction but potentially {@code false}
* for a savepoint-based nested transaction scope if the savepoint management
* is explicitly exposed (such as on {@link TransactionStatus}). A combined
* check for any kind of nested execution is provided by {@link #isNested()}.
* <p>The default implementation returns {@code true}.
* @see #hasTransaction()
* @see #isNested()
* @see TransactionStatus#hasSavepoint()
*/
default boolean isNewTransaction() {
return true;
}
/**
* Return if this transaction executes in a nested fashion within another.
* <p>The default implementation returns {@code false}.
* @since 6.1
* @see #hasTransaction()
* @see #isNewTransaction()
* @see TransactionDefinition#PROPAGATION_NESTED
*/
default boolean isNested() {
return false;
}
/**
* Return if this transaction is defined as read-only transaction.
* <p>The default implementation returns {@code false}.
* @since 6.1
* @see TransactionDefinition#isReadOnly()
*/
default boolean isReadOnly() {
return false;
}
/**
* Set the transaction rollback-only. This instructs the transaction manager
* that the only possible outcome of the transaction may be a rollback, as
* alternative to throwing an exception which would in turn trigger a rollback.
* <p>The default implementation throws an UnsupportedOperationException.
* @see #isRollbackOnly()
*/
default void setRollbackOnly() {
throw new UnsupportedOperationException("setRollbackOnly not supported");
}
/**
* Return whether the transaction has been marked as rollback-only
* (either by the application or by the transaction infrastructure).
* <p>The default implementation returns {@code false}.
* @see #setRollbackOnly()
*/
default boolean isRollbackOnly() {
return false;
}
/**
* Return whether this transaction is completed, that is,
* whether it has already been committed or rolled back.
* <p>The default implementation returns {@code false}.
*/
default boolean isCompleted() {
return false;
}
}
// 1. 是否是新事务
boolean isNewTransaction();
// 2. 是否标记为 只回滚
boolean isRollbackOnly();
// 3. 事务是否已完成(提交/回滚)
boolean isCompleted();
// 4. 是否是只读事务
boolean isReadOnly();
// 5. 是否被标记为 必须回滚
default boolean isRollbackOnly()
in short 可以理解为一个事务的状态: 是否是新事务, 是否是序列化, 是否是嵌套, 是否是只读的等
对于这个状态对象关键的点是, 在多层嵌套时, 主要在:
org.springframework.transaction.support.AbstractPlatformTransactionManager#handleExistingTransaction 中
视情况(主要是根据事务的传播特性, 该方法也是处理多层事务的核心方法) 创建或修改事务状态中的属性
对于线程绑定事务管理对象 TransactionSynchronizationManager
org.springframework.transaction.support.TransactionSynchronizationManager
public abstract class TransactionSynchronizationManager {
/**
* 线程私有事务资源
*/
private static final ThreadLocal<Map<Object, Object>> resources =
new NamedThreadLocal<>("Transactional resources");
/**
* 事务同步?
*/
private static final ThreadLocal<Set<TransactionSynchronization>> synchronizations =
new NamedThreadLocal<>("Transaction synchronizations");
/**
* 当前事务的 名称
*/
private static final ThreadLocal<String> currentTransactionName =
new NamedThreadLocal<>("Current transaction name");
/**
* 当前事务 是否只读
*/
private static final ThreadLocal<Boolean> currentTransactionReadOnly =
new NamedThreadLocal<>("Current transaction read-only status");
/**
* 当前事务的 隔离级别
*/
private static final ThreadLocal<Integer> currentTransactionIsolationLevel =
new NamedThreadLocal<>("Current transaction isolation level");
/**
* 事务是否实际激活
*/
private static final ThreadLocal<Boolean> actualTransactionActive =
new NamedThreadLocal<>("Actual transaction active");
/**
* Retrieve a resource for the given key that is bound to the current thread.
* @param key the key to check (usually the resource factory)
* @return a value bound to the current thread (usually the active
* resource object), or {@code null} if none
* @see ResourceTransactionManager#getResourceFactory()
*/
@Nullable
public static Object getResource(Object key) {
Object actualKey = TransactionSynchronizationUtils.unwrapResourceIfNecessary(key);
return doGetResource(actualKey);
}
/**
* Actually check the value of the resource that is bound for the given key.
*/
@Nullable
private static Object doGetResource(Object actualKey) {
Map<Object, Object> map = resources.get();
if (map == null) {
return null;
}
Object value = map.get(actualKey);
// Transparently remove ResourceHolder that was marked as void...
if (value instanceof ResourceHolder resourceHolder && resourceHolder.isVoid()) {
map.remove(actualKey);
// Remove entire ThreadLocal if empty...
if (map.isEmpty()) {
resources.remove();
}
value = null;
}
return value;
}
/**
* Bind the given resource for the given key to the current thread.
* @param key the key to bind the value to (usually the resource factory)
* @param value the value to bind (usually the active resource object)
* @throws IllegalStateException if there is already a value bound to the thread
* @see ResourceTransactionManager#getResourceFactory()
*/
public static void bindResource(Object key, Object value) throws IllegalStateException {
Object actualKey = TransactionSynchronizationUtils.unwrapResourceIfNecessary(key);
Assert.notNull(value, "Value must not be null");
Map<Object, Object> map = resources.get();
// set ThreadLocal Map if none found
if (map == null) {
map = new HashMap<>();
resources.set(map);
}
Object oldValue = map.put(actualKey, value);
// Transparently suppress a ResourceHolder that was marked as void...
if (oldValue instanceof ResourceHolder resourceHolder && resourceHolder.isVoid()) {
oldValue = null;
}
if (oldValue != null) {
throw new IllegalStateException(
"Already value [" + oldValue + "] for key [" + actualKey + "] bound to thread");
}
}
...........
可以看到有相当多的 ThreadLocal 变量, 它就是负责将事务信息与当前线程绑定的
绑定的源码逻辑
org.springframework.jdbc.datasource.DataSourceTransactionManager#doBegin
/**
*
* 真正在数据库中支持事务,
* 1. 从数据源中获取链接
* 2. 设置事务的隔离级别
* 3. 关闭连接的自动提交
* 4. 绑定连接到线程中 TransactionSynchronizationManager.bindResource(obtainDataSource(), txObject.getConnectionHolder());
*
* so , 如果想要复用或者是适配 Spring 的事务支持的数据库连接可以这么拿:
* ConnectionHolder conHolder = (ConnectionHolder) TransactionSynchronizationManager.getResource(obtainDataSource());
*
*/
@Override
protected void doBegin(Object transaction, TransactionDefinition definition) {
DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
Connection con = null;
try {
/**
* 如果 ConnectionHolder 中没有数据库连接 则从数据源中获取,再存到[事务上下文] txObject对象中
* (真正的从数据源获取JDBC连接)
*/
if (!txObject.hasConnectionHolder() ||
txObject.getConnectionHolder().isSynchronizedWithTransaction()) {
Connection newCon = obtainDataSource().getConnection();
if (logger.isDebugEnabled()) {
logger.debug("Acquired Connection [" + newCon + "] for JDBC transaction");
}
txObject.setConnectionHolder(new ConnectionHolder(newCon), true);
}
txObject.getConnectionHolder().setSynchronizedWithTransaction(true);
con = txObject.getConnectionHolder().getConnection();
/**
* 设置事务隔离级别
*/
Integer previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(con, definition);
txObject.setPreviousIsolationLevel(previousIsolationLevel);
txObject.setReadOnly(definition.isReadOnly());
// 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).
/**
* 关闭自动提交, 由 Spring 负责管理了
*/
if (con.getAutoCommit()) {
txObject.setMustRestoreAutoCommit(true);
if (logger.isDebugEnabled()) {
logger.debug("Switching JDBC Connection [" + con + "] to manual commit");
}
con.setAutoCommit(false);
}
/**
* 判断是否 需要设置为只读事务
*/
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()) {
/**
* 将 ConnectionHolder 绑定到当前线程中 (ThreadLocal)
*
* 如果想要复用或者是适配 Spring 的事务支持可以这么拿:
* ConnectionHolder conHolder = (ConnectionHolder) TransactionSynchronizationManager.getResource(obtainDataSource());
* 数据库的连接
*
* > ConnectionHolder 可以理解为包装了数据库的连接, 不重要
*/
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);
}
}
获取/复用的数据库连接的源码逻辑
org.springframework.jdbc.datasource.DataSourceTransactionManager#doGetTransaction
@Override
protected Object doGetTransaction() {
/**
* 1. 创建一个DataSourceTransactionObject 封装对象, 可以理解为数据源上下文, 它包含:
* ConnectionHolder 数据库连接Holder对象
* newConnectionHolder : 是否是新连接 属性
* savepointAllowed: 是否允许'保存点'
* readOnly: 是否只读
*
*/
DataSourceTransactionObject txObject = new DataSourceTransactionObject();
//
/**
* 设置允许'保存点'
*/
txObject.setSavepointAllowed(isNestedTransactionAllowed());
/**
* 2. 从[事务同步管理器]中获取连接持有器, Holder 持有一个数据库连接, 如果是第一次获取则是 null
* 事务同步管理器: (TransactionSynchronizationManager): 该对象管理的资源都是绑定到当前事务中的; 内部使用的 ThreadLocal 存储的
* 如果没有事务, 第一次获取则是 null,
* 如果之前有事务, 将会获取的同一个 ConnectionHolder
* 将获取到的ConnectionHolder 存到 DataSourceTransactionObject
*
* 总之核心逻辑就是复用事务连接
*/
ConnectionHolder conHolder =
(ConnectionHolder) TransactionSynchronizationManager.getResource(obtainDataSource());
txObject.setConnectionHolder(conHolder, false);
/**
* 放到 事务上下文
*/
return txObject;
}
重中之重的是: 的第三方扩展库/框架 都是通过这种方式支持Spring 声明式事务的, 见后文!
关键的源码流程
拦截器主流程入口
org.springframework.transaction.interceptor.TransactionAspectSupport#invokeWithinTransaction
/**
* General delegate for around-advice-based subclasses, delegating to several other template
* methods on this class. Able to handle {@link CallbackPreferringPlatformTransactionManager}
* as well as regular {@link PlatformTransactionManager} implementations and
* {@link ReactiveTransactionManager} implementations for reactive return types.
* @param method the Method being invoked
* @param targetClass the target class that we're invoking the method on
* @param invocation the callback to use for proceeding with the target invocation
* @return the return value of the method, if any
* @throws Throwable propagated from the target invocation
*/
@Nullable
protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass,
final InvocationCallback invocation) throws Throwable {
/**
* 获取事务属性源
* 即: <tx:attributes> 标签配置的
*/
// If the transaction attribute is null, the method is non-transactional.
TransactionAttributeSource tas = getTransactionAttributeSource();
/**
* 1. 通过目标方法去匹配, 拿到对应的属性配置(TransactionAttribute), 比如: 是否只读, 事务传播属性, rollbackOn 等
*/
final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);
/**
* 2. 拿到对应的事务管理器对象 (bean) TransactionManager
*/
final TransactionManager tm = determineTransactionManager(txAttr);
if (this.reactiveAdapterRegistry != null && tm instanceof ReactiveTransactionManager rtm) {
boolean isSuspendingFunction = KotlinDetector.isSuspendingFunction(method);
boolean hasSuspendingFlowReturnType = isSuspendingFunction &&
COROUTINES_FLOW_CLASS_NAME.equals(new MethodParameter(method, -1).getParameterType().getName());
if (isSuspendingFunction && !(invocation instanceof CoroutinesInvocationCallback)) {
throw new IllegalStateException("Coroutines invocation not supported: " + method);
}
CoroutinesInvocationCallback corInv = (isSuspendingFunction ? (CoroutinesInvocationCallback) invocation : null);
ReactiveTransactionSupport txSupport = this.transactionSupportCache.computeIfAbsent(method, key -> {
Class<?> reactiveType =
(isSuspendingFunction ? (hasSuspendingFlowReturnType ? Flux.class : Mono.class) : method.getReturnType());
ReactiveAdapter adapter = this.reactiveAdapterRegistry.getAdapter(reactiveType);
if (adapter == null) {
throw new IllegalStateException("Cannot apply reactive transaction to non-reactive return type: " +
method.getReturnType());
}
return new ReactiveTransactionSupport(adapter);
});
InvocationCallback callback = invocation;
if (corInv != null) {
callback = () -> KotlinDelegate.invokeSuspendingFunction(method, corInv);
}
return txSupport.invokeWithinTransaction(method, targetClass, callback, txAttr, rtm);
}
PlatformTransactionManager ptm = asPlatformTransactionManager(tm);
/**
* 3. 生成获取到事务方法的唯一ID
*/
final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);
if (txAttr == null || !(ptm instanceof CallbackPreferringPlatformTransactionManager cpptm)) {
/**
* 4. 使用 TransactionManager 创建事务, 获取到事务信息对象 (TransactionInfo)
*/
// Standard transaction demarcation with getTransaction and commit/rollback calls.
TransactionInfo txInfo = createTransactionIfNecessary(ptm, txAttr, joinpointIdentification);
Object retVal;
try {
/**
* 5. 以事务执行调用, 回调方法
* retVal 是dao方法(原始方法) 执行的返回值
*/
// 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) {
/**
* 6. 执行异常, 执行异常回滚操作
*/
// target invocation exception
completeTransactionAfterThrowing(txInfo, ex);
/**
* 注意这里还要再抛出去, 给外层事务知道 内层执行出现异常
*/
throw ex;
}
finally {
/**
* 7. 不管异常与否, 清除当前线程的[事务上下文]信息
* 这个是在{@link org.springframework.transaction.interceptor.TransactionAspectSupport#createTransactionIfNecessary(org.springframework.transaction.PlatformTransactionManager, org.springframework.transaction.interceptor.TransactionAttribute, java.lang.String)}
* 中返回时 prepareTransactionInfo方法中,调用了 `txInfo.newTransactionStatus(status);` 保存到 ThreadLocal 中的
*/
cleanupTransactionInfo(txInfo);
}
if (retVal != null && txAttr != null) {
TransactionStatus status = txInfo.getTransactionStatus();
if (status != null) {
if (retVal instanceof Future<?> future && future.isDone()) {
try {
future.get();
}
catch (ExecutionException ex) {
if (txAttr.rollbackOn(ex.getCause())) {
status.setRollbackOnly();
}
}
catch (InterruptedException ex) {
Thread.currentThread().interrupt();
}
}
else if (vavrPresent && VavrDelegate.isVavrTry(retVal)) {
// Set rollback-only in case of Vavr failure matching our rollback rules...
retVal = VavrDelegate.evaluateTryFailure(retVal, txAttr, status);
}
}
}
/**
* 8. 执行正常,执行正常提交处理
*/
commitTransactionAfterReturning(txInfo);
return retVal;
}
else {
.....
}
创建 TransactionInfo
使用 TransactionManager 创建事务, 获取到事务的上下文对象 (TransactionInfo)
org.springframework.transaction.interceptor.TransactionAspectSupport#createTransactionIfNecessary
protected TransactionInfo createTransactionIfNecessary(@Nullable PlatformTransactionManager tm,
@Nullable TransactionAttribute txAttr, final String joinpointIdentification) {
/**
* 包装了一下事务源属性
*/
// If no name specified, apply method identification as transaction name.
if (txAttr != null && txAttr.getName() == null) {
txAttr = new DelegatingTransactionAttribute(txAttr) {
@Override
public String getName() {
return joinpointIdentification;
}
};
}
/**
* 获取[事务状态]: 表示
* 是否 新事务
* 是否 有保存点
* 是否 只回滚
* 是否 完成
*/
TransactionStatus status = null;
if (txAttr != null) {
if (tm != null) {
/**
* 1. 获取到一个封装对象: 可以理解为事务的状态
* * 它包括: 是否只读, 是否允许'保存点', 从[事务同步管理器]获取 ConnectionHolder (注意第一次获取'无事务', Holder的connect是null的 );
*
* 2. 判断当前是否存在事务, 判断依据是 ConnectionHolder 内部 Active 标识符
* * 如果存在则, 处理事务传播特性
* * {@link org.springframework.transaction.support.AbstractPlatformTransactionManager#handleExistingTransaction(org.springframework.transaction.TransactionDefinition, java.lang.Object, boolean)}
*
* 3. 判断一下当前事务传播特性, 创建新的事务
* * 在这里如果是 REQUIRED, REQUIRES_NEW, NESTED 传播特性, 才需要需要创建事务
*
* 4. 开始事务
* 创建一个[事务状态]对象, 如果没有 数据库连接 则从数据源 中获取, 封装为 ConnectionHolder, 并赋值给[事务上下文]对象
* 开始事务, 其实就是设置数据库连接的一些属性:
* 关闭自动提交, 由Spring 负责管理了
* 判断是否需要设置为只读事务
* 如果是新事务, 则绑定到当前线程中 (ThreadLocal)
* org.springframework.transaction.support.AbstractPlatformTransactionManager#startTransaction(org.springframework.transaction.TransactionDefinition, java.lang.Object, boolean, boolean, org.springframework.transaction.support.AbstractPlatformTransactionManager.SuspendedResourcesHolder)
*
* 见 {@link org.springframework.transaction.support.AbstractPlatformTransactionManager#getTransaction(org.springframework.transaction.TransactionDefinition)}
*/
status = tm.getTransaction(txAttr);
}
else {
if (logger.isDebugEnabled()) {
logger.debug("Skipping transactional joinpoint [" + joinpointIdentification +
"] because no transaction manager has been configured");
}
}
}
/**
* 见: {@link org.springframework.transaction.interceptor.TransactionAspectSupport#prepareTransactionInfo(org.springframework.transaction.PlatformTransactionManager, org.springframework.transaction.interceptor.TransactionAttribute, java.lang.String, org.springframework.transaction.TransactionStatus)}
*/
return prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);
}
获取事务
org.springframework.transaction.support.AbstractPlatformTransactionManager#getTransaction
/**
* This implementation handles propagation behavior. Delegates to
* {@code doGetTransaction}, {@code isExistingTransaction}
* and {@code doBegin}.
* @see #doGetTransaction
* @see #isExistingTransaction
* @see #doBegin
*/
@Override
public final TransactionStatus getTransaction(@Nullable TransactionDefinition definition)
throws TransactionException {
/**
* 将 TransactionStatus 和 事务方法唯一ID, 事务源属性 封装为 TransactionDefinition
*/
// Use defaults if no transaction definition given.
TransactionDefinition def = (definition != null ? definition : TransactionDefinition.withDefaults());
/**
* 1. 获取到一个封装对象(DataSourceTransactionObject): 可以理解为事务上下文
* 它包括: 是否只读, 是否允许'保存点', 从[事务同步管理器]获取到的 ConnectionHolder (注意第一次'无事务'获取的 连接持有器Holder的connect是null的 );
*
* [事务同步管理器](TransactionSynchronizationManager): 该对象管理的资源都是绑定到当前事务中的; 内部使用ThreadLocal 存储的
* org.springframework.jdbc.datasource.DataSourceTransactionManager#doGetTransaction() 设置允许'保存点'
*/
Object transaction = doGetTransaction();
boolean debugEnabled = logger.isDebugEnabled();
/**
* 2. 判断当前是否存在事务, 判断依据是 ConnectionHolder 内部 Active 标识符
* 如果存在则, 处理事务传播特性
* org.springframework.transaction.support.AbstractPlatformTransactionManager#handleExistingTransaction(org.springframework.transaction.TransactionDefinition, java.lang.Object, boolean)
*/
if (isExistingTransaction(transaction)) {
/**
* 如果当前存在事务, 则走这个分支
*/
// Existing transaction found -> check propagation behavior to find out how to behave.
return handleExistingTransaction(def, transaction, debugEnabled);
}
// Check definition settings for new transaction.
if (def.getTimeout() < TransactionDefinition.TIMEOUT_DEFAULT) {
throw new InvalidTimeoutException("Invalid transaction timeout", def.getTimeout());
}
/**
* 3. 判断一下当前事务传播特性, 创建新的事务
* 在这里如果是 REQUIRED, REQUIRES_NEW, NESTED 传播特性, 需要创建事务
*/
// No existing transaction found -> check propagation behavior to find out how to proceed.
if (def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) {
throw new IllegalTransactionStateException(
"No existing transaction found for transaction marked with propagation 'mandatory'");
}
else if (def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED ||
def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW ||
def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
/**
* 挂起事务 (当前没有事务)
*/
SuspendedResourcesHolder suspendedResources = suspend(null);
if (debugEnabled) {
logger.debug("Creating new transaction with name [" + def.getName() + "]: " + def);
}
try {
/**
* 4. 开始事务
* * 创建一个[事务状态]对象, 关键属性: 是否是新的、是否有保存点、是否只读、是否嵌套、是否为只回滚、是否完成。
* * 如果没有 数据库连接 则从数据源 中获取, 封装为 ConnectionHolder, 并赋值给[事务上下文]对象
* * 其实就是设置数据库连接的一些属性:
* * 关闭自动提交, 由Spring 负责管理了
* * 判断是否需要设置为只读事务
* * 如果是新事务, 则通过 [事务同步资源管理器] TransactionSynchronizationManager 绑定到当前线程中 (ThreadLocal)
*/
return startTransaction(def, transaction, false, debugEnabled, suspendedResources);
}
catch (RuntimeException | Error ex) {
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);
}
boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
return prepareTransactionStatus(def, null, true, newSynchronization, debugEnabled, null);
}
}
在已有事务的情况-处理事务的传播特性
在已有事务的情况下, 主要是处理事务的传播特性
org.springframework.transaction.support.AbstractPlatformTransactionManager#handleExistingTransaction
/**
* Create a TransactionStatus for an existing transaction.
*/
private TransactionStatus handleExistingTransaction(
TransactionDefinition definition, Object transaction, boolean debugEnabled)
throws TransactionException {
/**
* 注意一点 , 现在是外部有事务的情况
* transaction 是txObject
*/
/**
* 1.如果是 NEVER (不允许事务) 传播特性, 则抛出异常
*/
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NEVER) {
throw new IllegalTransactionStateException(
"Existing transaction found for transaction marked with propagation 'never'");
}
/**
* 2.如果是 NOT_SUPPORTED (不支持当前事务;总是以非事务的方式执行), 传播特性 挂起事务
*/
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NOT_SUPPORTED) {
if (debugEnabled) {
logger.debug("Suspending current transaction");
}
//挂起事务
Object suspendedResources = suspend(transaction);
boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
// 返回一个 无事务状态(TransactionStatus)
return prepareTransactionStatus(
definition, null, false, newSynchronization, debugEnabled, suspendedResources);
}
/**
* 3.如果是 REQUIRES_NEW 传播特性, 挂起当前事务
* 注意该特性:
* - 事务挂起后, 新的事务是完全独立的, 包括连接等等, 每个事务独立提交
* - 它的内层事务影响外层事务, 但是外层异常不影响内层事务
*/
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW) {
if (debugEnabled) {
logger.debug("Suspending current transaction, creating new transaction with name [" +
definition.getName() + "]");
}
/**
* 挂起当前事务, 何为挂起?
* 如果有事务的话
* 1. 将 DataSourceTransactionObject [事务上下文]中的 ConnectionHolder 设置为null
* 2. 从[事务同步管理器]中解除绑定: TransactionSynchronizationManager.unbindResource(obtainDataSource())
* 这样就拿不到对象,不会对事务资源进行复用
* 3. 挂起了, 下次还有恢复, 所以要保存被挂起的事务信息 (SuspendedResourcesHolder)
*
*/
SuspendedResourcesHolder suspendedResources = suspend(transaction);
try {
/**
* //开启新的事务
*/
return startTransaction(definition, transaction, false, debugEnabled, suspendedResources);
}
catch (RuntimeException | Error beginEx) {
resumeAfterBeginException(transaction, suspendedResources, beginEx);
throw beginEx;
}
}
/**
* 4.如果是 NESTED (总是以嵌套的方式执行, 可以无限嵌套, MySQL的实现是 基于事务的保存点 savepoint )传播特性
*/
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() + "]");
}
/**
* 使用保存点, 对于NESTED的事务 (空实现,恒等于true)
*/
if (useSavepointForNestedTransaction()) {
/**
* 4.1 创建一个新的[事务状态] DefaultTransactionStatus
*/
// Create savepoint within existing Spring-managed transaction,
// through the SavepointManager API implemented by TransactionStatus.
// Usually uses JDBC savepoints. Never activates Spring synchronization.
DefaultTransactionStatus status = newTransactionStatus(
definition, transaction, false, false, true, debugEnabled, null);
this.transactionExecutionListeners.forEach(listener -> listener.beforeBegin(status));
try {
/**
* 4.2 创建保存点
* 最终是使用 ConnectionHolder 进行创建保存点, 底层是调用JDBC的接口方法 java.sql.Connection#setSavepoint(java.lang.String)
* org.springframework.jdbc.datasource.ConnectionHolder#createSavepoint()
*/
status.createAndHoldSavepoint();
}
catch (RuntimeException | Error ex) {
this.transactionExecutionListeners.forEach(listener -> listener.afterBegin(status, ex));
throw ex;
}
this.transactionExecutionListeners.forEach(listener -> listener.afterBegin(status, null));
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.
return startTransaction(definition, transaction, true, debugEnabled, null);
}
}
// 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()) {
throw new IllegalTransactionStateException("Participating transaction with definition [" +
definition + "] specifies isolation level which is incompatible with existing transaction: " +
(currentIsolationLevel != null ?
DefaultTransactionDefinition.getIsolationLevelName(currentIsolationLevel) :
"(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);
}
无事务的情况-新建事务
org.springframework.transaction.support.AbstractPlatformTransactionManager#startTransaction
/**
* Start a new transaction.
*/
private TransactionStatus startTransaction(TransactionDefinition definition, Object transaction,
boolean nested, boolean debugEnabled, @Nullable SuspendedResourcesHolder suspendedResources) {
boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
/**
* 1. 创建一个[事务状态]对象
* 包括事务: 是否是新的、是否有保存点、是否只读、是否嵌套、是否为只回滚、是否完成。
*/
DefaultTransactionStatus status = newTransactionStatus(
definition, transaction, true, newSynchronization, nested, debugEnabled, suspendedResources);
this.transactionExecutionListeners.forEach(listener -> listener.beforeBegin(status));
try {
/**
* 2. 如果没有 数据库连接 则从数据源 中获取, 封装为 ConnectionHolder, 并赋值给[事务上下文]对象
* 设置数据库连的一些属性:
* 关闭自动提交, 由Spring 负责管理了
* 判断是否需要设置为只读事务
* 如果是新事务, 则绑定到当前线程中 (ThreadLocal)
*
* {@link org.springframework.jdbc.datasource.DataSourceTransactionManager#doBegin(java.lang.Object, org.springframework.transaction.TransactionDefinition)}
*/
doBegin(transaction, definition);
}
catch (RuntimeException | Error ex) {
this.transactionExecutionListeners.forEach(listener -> listener.afterBegin(status, ex));
throw ex;
}
prepareSynchronization(status, definition);
this.transactionExecutionListeners.forEach(listener -> listener.afterBegin(status, null));
return status;
}
事务方法执行异常情况
org.springframework.transaction.interceptor.TransactionAspectSupport#completeTransactionAfterThrowing
/**
* Handle a throwable, completing the transaction.
* We may commit or roll back, depending on the configuration.
* @param txInfo information about the current transaction
* @param ex throwable encountered
*/
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);
}
/**
* 1. 匹配回滚的异常
* txInfo.transactionAttribute.rollbackOn(ex) 匹配回滚的异常
*/
if (txInfo.transactionAttribute != null && txInfo.transactionAttribute.rollbackOn(ex)) {
try {
/**
* 2. 设置回滚状态
*/
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 {
// 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 | Error ex2) {
logger.error("Application exception overridden by commit exception", ex);
throw ex2;
}
}
}
}
事务方法执行正常情况
org.springframework.transaction.interceptor.TransactionAspectSupport#commitTransactionAfterReturning
/**
* Execute after successful completion of call, but not after an exception was handled.
* Do nothing if we didn't create a transaction.
* @param txInfo information about the current transaction
*/
protected void commitTransactionAfterReturning(@Nullable TransactionInfo txInfo) {
if (txInfo != null && txInfo.getTransactionStatus() != null) {
if (logger.isTraceEnabled()) {
logger.trace("Completing transaction for [" + txInfo.getJoinpointIdentification() + "]");
}
/**
* 获取到当前的 TransactionStatus 提交到 TransactionManager
* 注意并不一定是数据库提交, 取决与 TransactionStatus 的状态实现, 有可能是回滚, 空提交
*/
txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());
}
}
嵌套恢复线程中 TransactionInfo 信息
这个是在{@link org.springframework.transaction.interceptor.TransactionAspectSupport#createTransactionIfNecessary(org.springframework.transaction.PlatformTransactionManager, org.springframework.transaction.interceptor.TransactionAttribute, java.lang.String)}
中返回时 prepareTransactionInfo方法中,调用了 txInfo.newTransactionStatus(status); 保存到 ThreadLocal 中的
/**
* Reset the TransactionInfo ThreadLocal.
* <p>Call this in all cases: exception or normal return!
* @param txInfo information about the current transaction (may be {@code null})
*/
protected void cleanupTransactionInfo(@Nullable TransactionInfo txInfo) {
if (txInfo != null) {
txInfo.restoreThreadLocalStatus();
}
}
调用流程汇总图

https://img2024.cnblogs.com/blog/3723410/202603/3723410-20260323222541707-574711567.png
底层处理事务的源码
事务的开启
如果ConnectionHolder 中没有数据库连接 则从数据源中获取, (真正的从数据源获取JDBC连接), 关闭自动提交,绑定到线程
org.springframework.jdbc.datasource.DataSourceTransactionManager#doBegin
/**
*
* 真正在数据库中支持事务,
* 1. 从数据源中获取链接
* 2. 设置事务的隔离级别
* 3. 关闭连接的自动提交
* 4. 绑定连接到线程中 TransactionSynchronizationManager.bindResource(obtainDataSource(), txObject.getConnectionHolder());
* so , 如果想要复用或者是适配 Spring 的事务支持的数据库连接可以这么拿:
* ConnectionHolder conHolder = (ConnectionHolder) TransactionSynchronizationManager.getResource(obtainDataSource());
*
*/
@Override
protected void doBegin(Object transaction, TransactionDefinition definition) {
DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
Connection con = null;
try {
/**
* 如果ConnectionHolder 中没有数据库连接 则从数据源中获取,再存到[事务上下文]对象中
* (真正的从数据源获取JDBC连接)
*/
if (!txObject.hasConnectionHolder() ||
txObject.getConnectionHolder().isSynchronizedWithTransaction()) {
Connection newCon = obtainDataSource().getConnection();
if (logger.isDebugEnabled()) {
logger.debug("Acquired Connection [" + newCon + "] for JDBC transaction");
}
txObject.setConnectionHolder(new ConnectionHolder(newCon), true);
}
txObject.getConnectionHolder().setSynchronizedWithTransaction(true);
con = txObject.getConnectionHolder().getConnection();
/**
* 设置事务隔离级别
*/
Integer previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(con, definition);
txObject.setPreviousIsolationLevel(previousIsolationLevel);
txObject.setReadOnly(definition.isReadOnly());
// 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).
/**
* 关闭自动提交, 由 Spring 负责管理了
*/
if (con.getAutoCommit()) {
txObject.setMustRestoreAutoCommit(true);
if (logger.isDebugEnabled()) {
logger.debug("Switching JDBC Connection [" + con + "] to manual commit");
}
con.setAutoCommit(false);
}
/**
* 判断是否 需要设置为只读事务
*/
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()) {
/**
* 将 ConnectionHolder 绑定到当前线程中 (ThreadLocal)
* 下次再拿的话可以这么拿:
* ConnectionHolder conHolder = (ConnectionHolder) TransactionSynchronizationManager.getResource(obtainDataSource()); * * > 可以理解 ConnectionHolder 包装了数据库的连接
*/
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);
}
}
事务的提交
判断一下 TransactionStatus 中状态, 决定是否要回滚
org.springframework.transaction.support.AbstractPlatformTransactionManager#commit
/**
* This implementation of commit handles participating in existing
* transactions and programmatic rollback requests.
* Delegates to {@code isRollbackOnly}, {@code doCommit}
* and {@code rollback}.
* @see org.springframework.transaction.TransactionStatus#isRollbackOnly()
* @see #doCommit
* @see #rollback
*/
@Override
public final void commit(TransactionStatus status) throws TransactionException {
if (status.isCompleted()) {
throw new IllegalTransactionStateException(
"Transaction is already completed - do not call commit or rollback more than once per transaction");
}
DefaultTransactionStatus defStatus = (DefaultTransactionStatus) status;
/**
* 1. 判断 [事务状态] 是否设置了回滚
*/
if (defStatus.isLocalRollbackOnly()) {
if (defStatus.isDebug()) {
logger.debug("Transactional code has requested rollback");
}
processRollback(defStatus, false);
return;
}
/**
* 2. 判断 [事务状态] 是否设置了设置了全局回滚
* 这里会拿到 ConnectHolder 判断其回滚标记
*/
if (!shouldCommitOnGlobalRollbackOnly() && defStatus.isGlobalRollbackOnly()) {
if (defStatus.isDebug()) {
logger.debug("Global transaction is marked as rollback-only but transactional code requested commit");
}
processRollback(defStatus, true);
return;
}
/**
* 3. 处理提交
*/
processCommit(defStatus);
}
触发一些钩子, 只有是 最外层事务才真正的JDBC提交
org.springframework.transaction.support.AbstractPlatformTransactionManager#processCommit
private void processCommit(DefaultTransactionStatus status) throws TransactionException {
try {
boolean beforeCompletionInvoked = false;
boolean commitListenerInvoked = false;
try {
boolean unexpectedRollback = false;
//预留 hook方法
prepareForCommit(status);
triggerBeforeCommit(status);
triggerBeforeCompletion(status);
beforeCompletionInvoked = true;
if (status.hasSavepoint()) {
/**
* 1. 是否有事务保存点 (NESTED 才会有保存点)
* 有就释放保存点
*/
if (status.isDebug()) {
logger.debug("Releasing transaction savepoint");
}
unexpectedRollback = status.isGlobalRollbackOnly();
this.transactionExecutionListeners.forEach(listener -> listener.beforeCommit(status));
commitListenerInvoked = true;
status.releaseHeldSavepoint();
}
else if (status.isNewTransaction()) {
/**
* 2. 是否是新事务, 即 是最外层事务才真正的JDBC提交
*/
if (status.isDebug()) {
logger.debug("Initiating transaction commit");
}
unexpectedRollback = status.isGlobalRollbackOnly();
this.transactionExecutionListeners.forEach(listener -> listener.beforeCommit(status));
commitListenerInvoked = true;
/**
* 真正的JDBC提交
*/
doCommit(status);
}
......
真正的 JDBC层提交
org.springframework.jdbc.datasource.DataSourceTransactionManager#doCommit
@Override
protected void doCommit(DefaultTransactionStatus status) {
DataSourceTransactionObject txObject = (DataSourceTransactionObject) status.getTransaction();
Connection con = txObject.getConnectionHolder().getConnection();
if (status.isDebug()) {
logger.debug("Committing JDBC transaction on Connection [" + con + "]");
} try {
con.commit();
} catch (SQLException ex) {
throw translateException("JDBC commit", ex);
}}
事务的回滚
跟提交同理, 只有最外层的才应该真正的提交
org.springframework.transaction.support.AbstractPlatformTransactionManager#processRollback
/**
* Process an actual rollback.
* The completed flag has already been checked.
* @param status object representing the transaction
* @throws TransactionException in case of rollback failure
*/
private void processRollback(DefaultTransactionStatus status, boolean unexpected) {
try {
boolean unexpectedRollback = unexpected;
boolean rollbackListenerInvoked = false;
try {
/**
* 1. 如果事务状态有保存点, 将事务状态回滚到设置的保存点 (仅NESTED才会存在保存点)
*/
triggerBeforeCompletion(status);
if (status.hasSavepoint()) {
if (status.isDebug()) {
logger.debug("Rolling back transaction to savepoint");
}
this.transactionExecutionListeners.forEach(listener -> listener.beforeRollback(status));
rollbackListenerInvoked = true;
status.rollbackToHeldSavepoint();
}
else if (status.isNewTransaction()) {
/**
* 2. 如果是新(外层)事务的话, 真正执行回滚 (只有在最外层是执行回滚的)
*/
if (status.isDebug()) {
logger.debug("Initiating transaction rollback");
}
this.transactionExecutionListeners.forEach(listener -> listener.beforeRollback(status));
rollbackListenerInvoked = true;
/**
* 真正在数据库连接层 执行事务回滚
*/
doRollback(status);
}
else {
// Participating in larger transaction
if (status.hasTransaction()) {
if (status.isLocalRollbackOnly() || isGlobalRollbackOnParticipationFailure()) {
if (status.isDebug()) {
logger.debug("Participating transaction failed - marking existing transaction as rollback-only");
}
/**
* 3. 设置 ConnectionHolder 中的 RollbackOnly 标记状态
*/
doSetRollbackOnly(status);
}
else {
if (status.isDebug()) {
logger.debug("Participating transaction failed - letting transaction originator decide on rollback");
}
}
}
else {
logger.debug("Should roll back transaction but cannot - no transaction available");
}
// Unexpected rollback only matters here if we're asked to fail early
if (!isFailEarlyOnGlobalRollbackOnly()) {
/**
* 4. 设置非预期的回滚标记
*/
unexpectedRollback = false;
}
}
}
catch (RuntimeException | Error ex) {
triggerAfterCompletion(status, TransactionSynchronization.STATUS_UNKNOWN);
if (rollbackListenerInvoked) {
this.transactionExecutionListeners.forEach(listener -> listener.afterRollback(status, ex));
}
throw ex;
}
triggerAfterCompletion(status, TransactionSynchronization.STATUS_ROLLED_BACK);
if (rollbackListenerInvoked) {
this.transactionExecutionListeners.forEach(listener -> listener.afterRollback(status, null));
}
// Raise UnexpectedRollbackException if we had a global rollback-only marker
if (unexpectedRollback) {
throw new UnexpectedRollbackException(
"Transaction rolled back because it has been marked as rollback-only");
}
}
finally {
/**
* 5. 清除当前事务信息, 注意, 这里如果有被挂起的事务还会恢复它
*/
cleanupAfterCompletion(status);
}
}
真正的 JDBC层回滚
org.springframework.jdbc.datasource.DataSourceTransactionManager#doRollback
@Override
protected void doRollback(DefaultTransactionStatus status) {
DataSourceTransactionObject txObject = (DataSourceTransactionObject) status.getTransaction();
Connection con = txObject.getConnectionHolder().getConnection();
if (status.isDebug()) {
logger.debug("Rolling back JDBC transaction on Connection [" + con + "]");
}
try {
con.rollback();
}
catch (SQLException ex) {
throw translateException("JDBC rollback", ex);
}
}
最后, 看看第三方框架是如何支持Spring声明式事务的
JdbcTemplate 是怎么支持Spring声明式事务的?
org.springframework.jdbc.core.JdbcTemplate
关键在于确保数据源中获取的 JDBC连接 都是同一个, 而在声明式事务配置中, 无论是 dataSource 对象, 还是 jdbcTemplate Bean 都没有被代理; 从配置上, 来看也完全没有关联
其实是 JdbcTemplate 在获取连接时 适配了 Spring 事务相关的代码, 关键源码:
org.springframework.jdbc.core.JdbcTemplate#execute(org.springframework.jdbc.core.CallableStatementCreator, org.springframework.jdbc.core.CallableStatementCallback<T>)org.springframework.jdbc.datasource.DataSourceUtils#getConnectionorg.springframework.jdbc.datasource.DataSourceUtils#doGetConnection
public static Connection doGetConnection(DataSource dataSource) throws SQLException {
Assert.notNull(dataSource, "No DataSource specified");
//从 TransactionSynchronizationManager 获取连接 (由Spring声明式事务处理的连接)
ConnectionHolder conHolder = (ConnectionHolder) TransactionSynchronizationManager.getResource(dataSource);
if (conHolder != null && (conHolder.hasConnection() || conHolder.isSynchronizedWithTransaction())) {
conHolder.requested();
if (!conHolder.hasConnection()) {
logger.debug("Fetching resumed JDBC Connection from DataSource");
conHolder.setConnection(fetchConnection(dataSource));
}
return conHolder.getConnection();
}
// Else we either got no holder or an empty thread-bound holder here.
logger.debug("Fetching JDBC Connection from DataSource");
Connection con = fetchConnection(dataSource);
......
MyBatis 是怎么支持Spring声明式事务的?
org.mybatis.spring.transaction.SpringManagedTransaction
org.springframework.jdbc.datasource.DataSourceUtils#doGetConnection
/**
* Actually obtain a JDBC Connection from the given DataSource.
* Same as {@link #getConnection}, but throwing the original SQLException.
* <p>Is aware of a corresponding Connection bound to the current thread, for example
* when using {@link DataSourceTransactionManager}. Will bind a Connection to the thread
* if transaction synchronization is active (for example, if in a JTA transaction).
* <p>Directly accessed by {@link TransactionAwareDataSourceProxy}.
* @param dataSource the DataSource to obtain Connections from
* @return a JDBC Connection from the given DataSource
* @throws SQLException if thrown by JDBC methods
* @see #doReleaseConnection
*/
public static Connection doGetConnection(DataSource dataSource) throws SQLException {
Assert.notNull(dataSource, "No DataSource specified");
ConnectionHolder conHolder = (ConnectionHolder) TransactionSynchronizationManager.getResource(dataSource);
if (conHolder != null && (conHolder.hasConnection() || conHolder.isSynchronizedWithTransaction())) {
conHolder.requested();
if (!conHolder.hasConnection()) {
logger.debug("Fetching resumed JDBC Connection from DataSource");
conHolder.setConnection(fetchConnection(dataSource));
}
return conHolder.getConnection();
}
// Else we either got no holder or an empty thread-bound holder here.
logger.debug("Fetching JDBC Connection from DataSource");
Connection con = fetchConnection(dataSource);
if (TransactionSynchronizationManager.isSynchronizationActive()) {
try {
// Use same Connection for further JDBC actions within the transaction.
// Thread-bound object will get removed by synchronization at transaction completion.
ConnectionHolder holderToUse = conHolder;
if (holderToUse == null) {
holderToUse = new ConnectionHolder(con);
}
else {
holderToUse.setConnection(con);
}
holderToUse.requested();
TransactionSynchronizationManager.registerSynchronization(
new ConnectionSynchronization(holderToUse, dataSource));
holderToUse.setSynchronizedWithTransaction(true);
if (holderToUse != conHolder) {
TransactionSynchronizationManager.bindResource(dataSource, holderToUse);
}
}
catch (RuntimeException ex) {
// Unexpected exception from external delegation call -> close Connection and rethrow.
releaseConnection(con, dataSource);
throw ex;
}
}
return con;
}
Hibernate 是怎么支持Spring声明式事务的?
- 开启事务的源码
@Override
protected void doBegin(Object transaction, TransactionDefinition definition) {
HibernateTransactionObject txObject = (HibernateTransactionObject) transaction;
if (txObject.hasConnectionHolder() && !txObject.getConnectionHolder().isSynchronizedWithTransaction()) {
throw new IllegalTransactionStateException(
"Pre-bound JDBC Connection found! HibernateTransactionManager does not support " +
"running within DataSourceTransactionManager if told to manage the DataSource itself. " +
"It is recommended to use a single HibernateTransactionManager for all transactions " +
"on a single DataSource, no matter whether Hibernate or JDBC access.");
}
SessionImplementor session = null;
try {
if (!txObject.hasSessionHolder() || txObject.getSessionHolder().isSynchronizedWithTransaction()) {
Interceptor entityInterceptor = getEntityInterceptor();
Session newSession = (entityInterceptor != null ?
obtainSessionFactory().withOptions().interceptor(entityInterceptor).openSession() :
obtainSessionFactory().openSession());
if (this.sessionInitializer != null) {
this.sessionInitializer.accept(newSession);
}
if (logger.isDebugEnabled()) {
logger.debug("Opened new Session [" + newSession + "] for Hibernate transaction");
}
txObject.setSession(newSession);
}
session = txObject.getSessionHolder().getSession().unwrap(SessionImplementor.class);
boolean holdabilityNeeded = this.allowResultAccessAfterCompletion && !txObject.isNewSession();
boolean isolationLevelNeeded = (definition.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT);
if (holdabilityNeeded || isolationLevelNeeded || definition.isReadOnly()) {
if (this.prepareConnection && ConnectionReleaseMode.ON_CLOSE.equals(
session.getJdbcCoordinator().getLogicalConnection().getConnectionHandlingMode().getReleaseMode())) {
// We're allowed to change the transaction settings of the JDBC Connection.
if (logger.isDebugEnabled()) {
logger.debug("Preparing JDBC Connection of Hibernate Session [" + session + "]");
}
Connection con = session.connection();
Integer previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(con, definition);
txObject.setPreviousIsolationLevel(previousIsolationLevel);
txObject.setReadOnly(definition.isReadOnly());
if (this.allowResultAccessAfterCompletion && !txObject.isNewSession()) {
int currentHoldability = con.getHoldability();
if (currentHoldability != ResultSet.HOLD_CURSORS_OVER_COMMIT) {
txObject.setPreviousHoldability(currentHoldability);
con.setHoldability(ResultSet.HOLD_CURSORS_OVER_COMMIT);
}
}
txObject.connectionPrepared();
}
else {
// Not allowed to change the transaction settings of the JDBC Connection.
if (isolationLevelNeeded) {
// We should set a specific isolation level but are not allowed to...
throw new InvalidIsolationLevelException(
"HibernateTransactionManager is not allowed to support custom isolation levels: " +
"make sure that its 'prepareConnection' flag is on (the default) and that the " +
"Hibernate connection release mode is set to ON_CLOSE.");
}
if (logger.isDebugEnabled()) {
logger.debug("Not preparing JDBC Connection of Hibernate Session [" + session + "]");
}
}
}
if (definition.isReadOnly() && txObject.isNewSession()) {
// Just set to MANUAL in case of a new Session for this transaction.
session.setHibernateFlushMode(FlushMode.MANUAL);
// As of 5.1, we're also setting Hibernate's read-only entity mode by default.
session.setDefaultReadOnly(true);
}
if (!definition.isReadOnly() && !txObject.isNewSession()) {
// We need AUTO or COMMIT for a non-read-only transaction.
FlushMode flushMode = session.getHibernateFlushMode();
if (FlushMode.MANUAL.equals(flushMode)) {
session.setHibernateFlushMode(FlushMode.AUTO);
txObject.getSessionHolder().setPreviousFlushMode(flushMode);
}
}
Transaction hibTx;
// Register transaction timeout.
int timeout = determineTimeout(definition);
if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) {
// Use Hibernate's own transaction timeout mechanism on Hibernate 3.1+
// Applies to all statements, also to inserts, updates and deletes!
hibTx = session.getTransaction();
hibTx.setTimeout(timeout);
hibTx.begin();
}
else {
// Open a plain Hibernate transaction without specified timeout.
hibTx = session.beginTransaction();
}
// Add the Hibernate transaction to the session holder.
txObject.getSessionHolder().setTransaction(hibTx);
// Register the Hibernate Session's JDBC Connection for the DataSource, if set.
if (getDataSource() != null) {
ConnectionHolder conHolder = new ConnectionHolder(session::connection);
if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) {
conHolder.setTimeoutInSeconds(timeout);
}
if (logger.isDebugEnabled()) {
logger.debug("Exposing Hibernate transaction as JDBC [" + conHolder.getConnectionHandle() + "]");
}
TransactionSynchronizationManager.bindResource(getDataSource(), conHolder);
txObject.setConnectionHolder(conHolder);
}
// 绑定到线程
// Bind the session holder to the thread.
if (txObject.isNewSessionHolder()) {
TransactionSynchronizationManager.bindResource(obtainSessionFactory(), txObject.getSessionHolder());
}
txObject.getSessionHolder().setSynchronizedWithTransaction(true);
}
catch (Throwable ex) {
if (txObject.isNewSession()) {
try {
if (session != null && session.getTransaction().getStatus() == TransactionStatus.ACTIVE) {
session.getTransaction().rollback();
}
}
catch (Throwable ex2) {
logger.debug("Could not rollback Session after failed transaction begin", ex);
}
finally {
SessionFactoryUtils.closeSession(session);
txObject.setSessionHolder(null);
}
}
throw new CannotCreateTransactionException("Could not open Hibernate Session for transaction", ex);
}
}
- 复用的源码
org.springframework.orm.hibernate5.SpringSessionContext#currentSession
/**
* Retrieve the Spring-managed Session for the current thread, if any.
*/
@Override
public Session currentSession() throws HibernateException {
Object value = TransactionSynchronizationManager.getResource(this.sessionFactory);
if (value instanceof Session) {
return (Session) value;
}
else if (value instanceof SessionHolder) {
// HibernateTransactionManager
SessionHolder sessionHolder = (SessionHolder) value;
Session session = sessionHolder.getSession();
if (!sessionHolder.isSynchronizedWithTransaction() &&
TransactionSynchronizationManager.isSynchronizationActive()) {
TransactionSynchronizationManager.registerSynchronization(
new SpringSessionSynchronization(sessionHolder, this.sessionFactory, false));
sessionHolder.setSynchronizedWithTransaction(true);
// Switch to FlushMode.AUTO, as we have to assume a thread-bound Session
// with FlushMode.MANUAL, which needs to allow flushing within the transaction.
FlushMode flushMode = session.getHibernateFlushMode();
if (flushMode.equals(FlushMode.MANUAL) &&
!TransactionSynchronizationManager.isCurrentTransactionReadOnly()) {
session.setHibernateFlushMode(FlushMode.AUTO);
sessionHolder.setPreviousFlushMode(flushMode);
}
}
return session;
}
else if (value instanceof EntityManagerHolder) {
// JpaTransactionManager
return ((EntityManagerHolder) value).getEntityManager().unwrap(Session.class);
}
if (this.transactionManager != null && this.jtaSessionContext != null) {
try {
if (this.transactionManager.getStatus() == Status.STATUS_ACTIVE) {
Session session = this.jtaSessionContext.currentSession();
if (TransactionSynchronizationManager.isSynchronizationActive()) {
TransactionSynchronizationManager.registerSynchronization(
new SpringFlushSynchronization(session));
}
return session;
}
}
catch (SystemException ex) {
throw new HibernateException("JTA TransactionManager found but status check failed", ex);
}
}
if (TransactionSynchronizationManager.isSynchronizationActive()) {
Session session = this.sessionFactory.openSession();
if (TransactionSynchronizationManager.isCurrentTransactionReadOnly()) {
session.setHibernateFlushMode(FlushMode.MANUAL);
}
SessionHolder sessionHolder = new SessionHolder(session);
TransactionSynchronizationManager.registerSynchronization(
new SpringSessionSynchronization(sessionHolder, this.sessionFactory, true));
TransactionSynchronizationManager.bindResource(this.sessionFactory, sessionHolder);
sessionHolder.setSynchronizedWithTransaction(true);
return session;
}
else {
throw new HibernateException("Could not obtain transaction-synchronized Session for current thread");
}
}

浙公网安备 33010602011771号