事务是干什么用的?事务是应用程序中一系列严密的操作,所有操作必须成功完成,否则在每个操作中所作的所有更改都会被撤消。 也就是事务具有原子性,一个事务中的一系列的操作要么全部成功,要么一个都不做。
在了解事务的原理之前,我们先来看下一个简单的事务案例。
我们先来看下项目的结构:红框部分
其次,我的本地的数据库信息:
test
。user
。表结构如下:
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for user
-- ----------------------------
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
`id` int(11) NOT NULL,
`name` varchar(255) DEFAULT NULL,
`age` int(11) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
SET FOREIGN_KEY_CHECKS = 1;
pom
文件如下:
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-contextartifactId>
<version>5.3.3version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-txartifactId>
<version>5.2.9.RELEASEversion>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>5.1.39version>
dependency>
<dependency>
<groupId>org.apache.commonsgroupId>
<artifactId>commons-dbcp2artifactId>
<version>2.9.0version>
dependency>
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
<version>4.13version>
<scope>testscope>
dependency>
接下来我们看下代码部分:
User
类:
package com.tx;
public class User {
private int id;
private String name;
private int age;
public User(int id, String name, int age) {
this.id = id;
this.name = name;
this.age = age;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
UserMapper
类:
package com.tx;
import org.springframework.jdbc.core.RowMapper;
import java.sql.ResultSet;
import java.sql.SQLException;
public class UserMapper implements RowMapper {
@Override
public Object mapRow(ResultSet resultSet, int i) throws SQLException {
User user = new User(resultSet.getInt("id"),
resultSet.getString("name"),
resultSet.getInt("age"));
return user;
}
}
UserService
接口:
package com.tx;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
@Transactional(propagation = Propagation.REQUIRED)
public interface UserService {
void insert(User user) throws Exception;
}
UserService
接口实现类UserServiceImpl
:
package com.tx;
import org.apache.commons.dbcp2.BasicDataSource;
import org.springframework.jdbc.core.JdbcTemplate;
import java.sql.Types;
public class UserServiceImpl implements UserService {
private JdbcTemplate jdbcTemplate;
@Override
public void insert(User user) throws Exception {
jdbcTemplate.update("insert into user(id,name,age) values(?,?,?)",
new Object[]{user.getId(), user.getName(), user.getAge()},
new int[]{Types.INTEGER, Types.VARCHAR, Types.INTEGER});
System.out.println("数据添加成功!");
throw new RuntimeException("事务测试");
}
public void setDataSource(BasicDataSource dataSource) {
this.jdbcTemplate = new JdbcTemplate(dataSource);
}
}
Test
类:
package com.tx;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test {
public static void main(String[] args) throws Exception {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("tx/user.xml");
UserService userService = (UserService) context.getBean("userService");
User user = new User(1, "LJJ", 22);
userService.insert(user);
}
}
user.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:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">
<tx:annotation-driven transaction-manager="transactionManager"/>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/test"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</bean>
<bean id="userService" class="com.tx.UserServiceImpl">
<property name="dataSource" ref="dataSource"/>
</bean>
</beans>
程序运行后如下图所示
同时数据库中的数据并没有插入:可见程序回滚了。
若我将下述代码注释掉:
throw new RuntimeException("事务测试");
注意:
Spring默认情况下的事务处理只针对RuntimeException
方法进行回滚。
Mysql事务相关的知识,可进传送门Mysql技术内幕(四)–Mysql事务和备份
在学习AOP原理的时候,也是从XML配置入手,和AOP有关的配置文件为:
<aop:aspectj-autoproxy/>
那么同理,在本文的事务案例中,我们可以看到这么一个配置标签:
<tx:annotation-driven transaction-manager="transactionManager"/>
它作为事务的开关,因此我们从该配置作为入口进行深入学习。
有了前车之鉴,AOP对应的处理器为AopNamespaceHandler
,那么事务对应的处理器是不是TxNamespaceHandler
呢?搜一搜还真有!
我们来看下里面的init
方法:
public class TxNamespaceHandler extends NamespaceHandlerSupport {
@Override
public void init() {
registerBeanDefinitionParser("advice", new TxAdviceBeanDefinitionParser());
registerBeanDefinitionParser("annotation-driven", new AnnotationDrivenBeanDefinitionParser());
registerBeanDefinitionParser("jta-transaction-manager", new JtaTransactionManagerBeanDefinitionParser());
}
}
啥意思呢?也就是根据自定义标签的使用规则,当遇到tx:annotation-driven
标签的时候,Spring就会使用AnnotationDrivenBeanDefinitionParser
的parse()
函数进行解析:
class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser {
public BeanDefinition parse(Element element, ParserContext parserContext) {
registerTransactionalEventListenerFactory(parserContext);
String mode = element.getAttribute("mode");
if ("aspectj".equals(mode)) {
registerTransactionAspect(element, parserContext);
if (ClassUtils.isPresent("javax.transaction.Transactional", getClass().getClassLoader())) {
registerJtaTransactionAspect(element, parserContext);
}
}
else {
AopAutoProxyConfigurer.configureAutoProxyCreator(element, parserContext);
}
return null;
}
}
由于Spring中的事务是以AOP为基础的,因此这里会对mode
属性进行判断,是否使用AspectJ
的方式进行事务的切入。若需要,配置如下:
<tx:annotation-driven transaction-manager="transactionManager" mode="aspectj"/>
本文以默认的动态代理的分支进行讲解。
AopAutoProxyConfigurer.configureAutoProxyCreator(element, parserContext);
↓↓↓↓↓↓
private static class AopAutoProxyConfigurer {
public static void configureAutoProxyCreator(Element element, ParserContext parserContext) {
// 1.注册AOP的入口类
AopNamespaceUtils.registerAutoProxyCreatorIfNecessary(parserContext, element);
String txAdvisorBeanName = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME;
if (!parserContext.getRegistry().containsBeanDefinition(txAdvisorBeanName)) {
Object eleSource = parserContext.extractSource(element);
// 2.创建TransactionAttributeSource类型的bean ,即@Transactional注解的属性封装
RootBeanDefinition sourceDef = new RootBeanDefinition(
"org.springframework.transaction.annotation.AnnotationTransactionAttributeSource");
sourceDef.setSource(eleSource);
sourceDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
String sourceName = parserContext.getReaderContext().registerWithGeneratedName(sourceDef);
// 3.创建TransactionInterceptor类型的bean,即AOP的调用链
RootBeanDefinition interceptorDef = new RootBeanDefinition(TransactionInterceptor.class);
interceptorDef.setSource(eleSource);
interceptorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
// 4.拿到transaction-manager属性的值,参考
registerTransactionManager(element, interceptorDef);
interceptorDef.getPropertyValues().add("transactionAttributeSource", new RuntimeBeanReference(sourceName));
String interceptorName = parserContext.getReaderContext().registerWithGeneratedName(interceptorDef);
// 5.创建TransactionAttributeSourceAdvisor
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);
// 6.若配置了order属性,则加入到bean中
if (element.hasAttribute("order")) {
advisorDef.getPropertyValues().add("order", element.getAttribute("order"));
}
parserContext.getRegistry().registerBeanDefinition(txAdvisorBeanName, advisorDef);
// 7.创建 CompositeComponentDefinition
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);
}
}
}
此时我们来看下第一步代码:
AopNamespaceUtils.registerAutoProxyCreatorIfNecessary(parserContext, element);
点进去我发现,这个方法看起来非常非常的眼熟,如图:
而registerAutoProxyCreatorIfNecessary()
函数的主要作用是注册了一个InfrastructureAdvisorAutoProxyCreator
类。其类图关系如下:
到这里,就和AOP的实现原理非常的相似了,传送门:Spring源码系列:AOP实现,从2.2节开始。
那么本篇文章为了连贯性,就以文字的形式再来回顾以下这里的实现:
InfrastructureAdvisorAutoProxyCreator
类是BeanPostProcessor
接口的子类,因此会调用postProcessAfterInitialization()
方法。bean
对应的增强器。也因此说Spring事务是在AOP的基础上实现的。
但是出现分支点的代码在以下阶段:匹配候选增强器(过滤阶段)
/**
* @param advisor:增强对象
* @param targetClass:目标类
* @param hasIntroductions:是否含有引介增强
* @return
*/
public static boolean canApply(Advisor advisor, Class<?> targetClass, boolean hasIntroductions) {
// 1.如果是引介增强,则调用IntroductionAdvisor的getClassFilter.matches方法判断是否匹配
if (advisor instanceof IntroductionAdvisor) {
return ((IntroductionAdvisor) advisor).getClassFilter().matches(targetClass);
} else if (advisor instanceof PointcutAdvisor) {
// 2.如果是普通增强,调用canApply方法判断是否匹配
PointcutAdvisor pca = (PointcutAdvisor) advisor;
return canApply(pca.getPointcut(), targetClass, hasIntroductions);
} else {
return true;
}
}
我们知道canApply函数需要传入一个增强Advisor
对象。此时此刻,大家可以回顾下2.1小节
最初放出的源码的第五步。创建了个BeanFactoryTransactionAttributeSourceAdvisor
类型的实例。而其作为PointcutAdvisor
类的一个子类,因此上述canApply
函数会走第二个if分支
。
那么此时此刻,这个pca.getPointcut()
函数返回的对象到底是啥呢?来看下这个方法的实现类:
本篇文章可是围绕着事务来讲的呀,那毫无疑问的,咱们根据名字就知道肯定看上图中红框类TransactionAttributeSourceAdvisor
:
public class TransactionAttributeSourceAdvisor extends AbstractPointcutAdvisor {
private final TransactionAttributeSourcePointcut pointcut = new TransactionAttributeSourcePointcut() {
@Override
@Nullable
protected TransactionAttributeSource getTransactionAttributeSource() {
return (transactionInterceptor != null ? transactionInterceptor.getTransactionAttributeSource() : null);
}
};
@Override
public Pointcut getPointcut() {
return this.pointcut;
}
}
毫无疑问getPointcut
函数返回的是TransactionAttributeSourcePointcut
对象。
此时我们继续看canApply
方法:
// 获取目标类以及父类的所有的方法,进行一一匹配,查看方法和类上是否有事务注解,有的话就直接返回。
public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) {
// ...省略
for (Class<?> clazz : classes) {
// 通过反射获取目标类的所有方法,进行逐一检测
Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz);
// 获取所有方法(包括父类),任意一个匹配即返回true
for (Method method : methods) {
if (introductionAwareMethodMatcher != null ?
introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions) :
// 关注这行代码
methodMatcher.matches(method, targetClass)) {
return true;
}
}
}
return false;
}
我们关注到matches
函数,这里调用的是子类TransactionAttributeSourcePointcut
(通过getPointcut
函数返回的)中的实现:
@Override
public boolean matches(Method method, Class<?> targetClass) {
// 自定义标签解析的时候引入
TransactionAttributeSource tas = getTransactionAttributeSource();
return (tas == null || tas.getTransactionAttribute(method, targetClass) != null);
}
我们来关注下getTransactionAttribute
函数:
毫无疑问的,我们关注AbstractFallbackTransactionAttributeSource
类中的实现:
public TransactionAttribute getTransactionAttribute(Method method, @Nullable Class<?> targetClass) {
if (method.getDeclaringClass() == Object.class) {
return null;
}
// 1.先尝试从缓存中取
Object cacheKey = getCacheKey(method, targetClass);
TransactionAttribute cached = this.attributeCache.get(cacheKey);
if (cached != null) {
// ...省略
} else {
// 2.若缓存中没有,那么去创建
TransactionAttribute txAttr = computeTransactionAttribute(method, targetClass);
// ...省略
}
}
到这里,才真正的走向事务标签的一个提取,也就是computeTransactionAttribute
函数。我们先来总结下,这里花了大篇幅讲的内容,否则读者看着会比较混乱:
InfrastructureAdvisorAutoProxyCreator
类是BeanPostProcessor
接口的子类,因此会调用postProcessAfterInitialization()
方法。bean
对应的增强器。TransactionAttributeSourcePointcut
类捕获到,然后通过matches
函数创建对应的事务节点。getTransactionAttribute()
函数,其中主要通过computeTransactionAttribute()
函数来创建。那么接下来也就是关于事务原理的一个主流程了。
computeTransactionAttribute
函数:
@Nullable
protected TransactionAttribute computeTransactionAttribute(Method method, @Nullable Class<?> targetClass) {
// 1.非public方法的不可以增加事务
if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) {
return null;
}
Method specificMethod = AopUtils.getMostSpecificMethod(method, targetClass);
// 2.查看方法中是否存在事务声明
TransactionAttribute txAttr = findTransactionAttribute(specificMethod);
if (txAttr != null) {
return txAttr;
}
// 2.查看方法所在的类中是否存在事务声明
txAttr = findTransactionAttribute(specificMethod.getDeclaringClass());
if (txAttr != null && ClassUtils.isUserLevelMethod(method)) {
return txAttr;
}
// 3.若存在接口,则到接口中去寻找
if (specificMethod != method) {
// 3.1 查找接口方法
txAttr = findTransactionAttribute(method);
if (txAttr != null) {
return txAttr;
}
// 3.2 去接口的类中去寻找
txAttr = findTransactionAttribute(method.getDeclaringClass());
if (txAttr != null && ClassUtils.isUserLevelMethod(method)) {
return txAttr;
}
}
return null;
}
这个函数的目的一目了然:事务属性的获取,其来源可能有三种:
同时我们也可以看到,三种方式都是委派findTransactionAttribute
函数去执行匹配:
public class AnnotationTransactionAttributeSource extends AbstractFallbackTransactionAttributeSource
implements Serializable {
protected TransactionAttribute findTransactionAttribute(Method method) {
return determineTransactionAttribute(method);
}
↓↓↓↓↓↓↓↓
protected TransactionAttribute determineTransactionAttribute(AnnotatedElement element) {
// this.annotationParsers在 AnnotationTransactionAttributeSource 类初始化的时候,就加入了
// SpringTransactionAnnotationParser类。
for (TransactionAnnotationParser parser : this.annotationParsers) {
TransactionAttribute attr = parser.parseTransactionAnnotation(element);
if (attr != null) {
return attr;
}
}
return null;
}
}
我们来看下TransactionAnnotationParser.parseTransactionAnnotation()
函数:
public class SpringTransactionAnnotationParser implements TransactionAnnotationParser, Serializable {
public TransactionAttribute parseTransactionAnnotation(AnnotatedElement element) {
// 先判断当前类是否有@Transactional注解,有的话则进行属性的提取
AnnotationAttributes attributes = AnnotatedElementUtils.findMergedAnnotationAttributes(
element, Transactional.class, false, false);
if (attributes != null) {
// 进行属性的提取
return parseTransactionAnnotation(attributes);
}
else {
return null;
}
}
↓↓↓↓↓↓↓↓
protected TransactionAttribute parseTransactionAnnotation(AnnotationAttributes attributes) {
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());
String timeoutString = attributes.getString("timeoutString");
Assert.isTrue(!StringUtils.hasText(timeoutString) || rbta.getTimeout() < 0,
"Specify 'timeout' or 'timeoutString', not both");
rbta.setTimeoutString(timeoutString);
// 事务的读写性
rbta.setReadOnly(attributes.getBoolean("readOnly"));
// 可选的限定描述符,指定使用的事务管理器
rbta.setQualifier(attributes.getString("value"));
rbta.setLabels(Arrays.asList(attributes.getStringArray("label")));
List<RollbackRuleAttribute> rollbackRules = new ArrayList<>();
// 一组异常类,遇到时回滚
for (Class<?> rbRule : attributes.getClassArray("rollbackFor")) {
rollbackRules.add(new RollbackRuleAttribute(rbRule));
}
// 一组异常类名,遇到回滚,类型为string[]
for (String rbRule : attributes.getStringArray("rollbackForClassName")) {
rollbackRules.add(new RollbackRuleAttribute(rbRule));
}
// 一组异常类,遇到不回滚
for (Class<?> rbRule : attributes.getClassArray("noRollbackFor")) {
rollbackRules.add(new NoRollbackRuleAttribute(rbRule));
}
// 不会导致事务回滚的异常类名字数组
for (String rbRule : attributes.getStringArray("noRollbackForClassName")) {
rollbackRules.add(new NoRollbackRuleAttribute(rbRule));
}
rbta.setRollbackRules(rollbackRules);
return rbta;
}
}
到这里,就是对事务注解和相关属性的解析了。同时,事务的初始化工作也就结束了。
事务原理的前半部分是在AOP的基础上实现的:
@Transactional
注解或者相关属性,那么它是和事务增强器匹配的,则会被事务功能修饰。AOP代理
。BeanFactoryTransactionAttributeSourceAdvisor
类作为Advisor
的一个实现类,那么当代理调用的时候自然会调用该类的增强方法。而在2.1小节的第一个源码块中,解析事务定义标签的时候,Spring又将TransactionInterceptor
类注入了到了BeanFactoryTransactionAttributeSourceAdvisor
中(承上启下的感觉)。
TransactionInterceptor
进行增强。invoke
方法。本文章的第二章节可以说主要围绕着事务的初始化工作来展开介绍,那么本环节则侧重于事务的业务实现了。我们来看下其invoke
方法:
public class TransactionInterceptor extends TransactionAspectSupport implements MethodInterceptor, Serializable {
public Object invoke(MethodInvocation invocation) throws Throwable {
Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);
return invokeWithinTransaction(invocation.getMethod(), targetClass, new CoroutinesInvocationCallback() {
@Override
@Nullable
public Object proceedWithInvocation() throws Throwable {
return invocation.proceed();
}
@Override
public Object getTarget() {
return invocation.getThis();
}
@Override
public Object[] getArguments() {
return invocation.getArguments();
}
});
}
}
从这里可以看出这么几点:
TransactionInterceptor
类继承自MethodInterceptor
类。而MethodInterceptor
是个环绕通知,符合事务的开启、提交和回滚操作。TransactionAspectSupport
的invokeWithinTransaction
函数来执行。我们来看下invokeWithinTransaction
函数:
@Nullable
protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass,
final InvocationCallback invocation) throws Throwable {
// 1.获取对应的事务属性源
TransactionAttributeSource tas = getTransactionAttributeSource();
// 2.获取对应的事务属性
final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);
// 3.找到对应的事务管理器
final TransactionManager tm = determineTransactionManager(txAttr);
// ...省略
// 4.拿到目标方法的唯一标识
final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);
// 5.声明式处理
if (txAttr == null || !(ptm instanceof CallbackPreferringPlatformTransactionManager)) {
// 6.根据事务传播行为,判断是否有必要创建一个事务
TransactionInfo txInfo = createTransactionIfNecessary(ptm, txAttr, joinpointIdentification);
Object retVal;
try {
// 7.执行被增强的方法
retVal = invocation.proceedWithInvocation();
}
catch (Throwable ex) {
// 8.抛异常了,则进行回滚
completeTransactionAfterThrowing(txInfo, ex);
throw ex;
}
finally {
// 9.清除信息
cleanupTransactionInfo(txInfo);
}
if (retVal != null && vavrPresent && VavrDelegate.isVavrTry(retVal)) {
// Set rollback-only in case of Vavr failure matching our rollback rules...
TransactionStatus status = txInfo.getTransactionStatus();
if (status != null && txAttr != null) {
retVal = VavrDelegate.evaluateTryFailure(retVal, txAttr, status);
}
}
// 10.提交事务
commitTransactionAfterReturning(txInfo);
return retVal;
}
// 编程式事务
else {
// ...省略
}
}
上述代码用文字总结就是:
transactionManager
(事务管理器)。参考<tx:annotation-driven transaction-manager="transactionManager" mode="aspectj"/>
那么对于事务功能的执行来说,最重要的是三个部分:事务的创建、回滚的处理、事务的提交。我们先来看下创建事务的流程
入口代码为:
TransactionInfo txInfo = createTransactionIfNecessary(ptm, txAttr, joinpointIdentification);
↓↓↓↓↓↓↓↓
protected TransactionInfo createTransactionIfNecessary(@Nullable PlatformTransactionManager tm,
@Nullable TransactionAttribute txAttr, final String joinpointIdentification) {
// 1.若没有指定名称,则使用方法的唯一标识来封装 txAttr。(拿到事务的名称)
// TransactionAttribute:txAttr 由获取事务属性的时候生成,用于数据的承载。
if (txAttr != null && txAttr.getName() == null) {
txAttr = new DelegatingTransactionAttribute(txAttr) {
@Override
public String getName() {
return joinpointIdentification;
}
};
}
// 2.通过事务管理器获得一个事务的状态信息 (拿到事务的状态)
TransactionStatus status = null;
if (txAttr != null) {
if (tm != null) {
status = tm.getTransaction(txAttr);
}
else {
if (logger.isDebugEnabled()) {
logger.debug("Skipping transactional joinpoint [" + joinpointIdentification +
"] because no transaction manager has been configured");
}
}
}
// 3.根据指定的名称和status构建一个 TransactionInfo 事务信息存储对象。
return prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);
}
我们来看下第二步status = tm.getTransaction(txAttr);
这段核心代码,Spring主要在这段代码中来进行事务的一些准备工作。比如事务的获取和信息的构建:
status = tm.getTransaction(txAttr);
↓↓↓↓↓↓↓↓
@Override
public final TransactionStatus getTransaction(@Nullable TransactionDefinition definition)
throws TransactionException {
TransactionDefinition def = (definition != null ? definition : TransactionDefinition.withDefaults());
// 1.创建事务实例
Object transaction = doGetTransaction();
boolean debugEnabled = logger.isDebugEnabled();
// 2.判断当前线程是否存在事务
if (isExistingTransaction(transaction)) {
// 若存在事务,返回即可
return handleExistingTransaction(def, transaction, debugEnabled);
}
// 3.事务超时验证
if (def.getTimeout() < TransactionDefinition.TIMEOUT_DEFAULT) {
throw new InvalidTimeoutException("Invalid transaction timeout", def.getTimeout());
}
// 4.如果当前线程不存在事务,但是事务船舶类型被声明为 PROPAGATION_MANDATORY ,抛异常
if (def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) {
throw new IllegalTransactionStateException(
"No existing transaction found for transaction marked with propagation 'mandatory'");
}
// 5.新建事务
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 {
// 6.构建事务
return startTransaction(def, transaction, debugEnabled, suspendedResources);
}
// ...省略
}
// ...省略
}
我们来看下第一步,关于事务实例的获取过程:
// 抽象方法,具体交给子类实现来执行
Object transaction = doGetTransaction();
最终的实现则交由DataSourceTransactionManager
类来执行:
public class DataSourceTransactionManager extends AbstractPlatformTransactionManager
implements ResourceTransactionManager, InitializingBean {
@Override
protected Object doGetTransaction() {
// 主要创建一个基于JDBC的事务实例
DataSourceTransactionObject txObject = new DataSourceTransactionObject();
txObject.setSavepointAllowed(isNestedTransactionAllowed());
// 若当前线程已经记录了数据库连接,那么使用原有的连接
ConnectionHolder conHolder =
(ConnectionHolder) TransactionSynchronizationManager.getResource(obtainDataSource());
// false表示非新创建连接
txObject.setConnectionHolder(conHolder, false);
return txObject;
}
}
上述代码本身并没有什么可讲的,因为毕竟是在事务已存在的情况下才会走的逻辑。但是事务不存在的情况下,就会着手于事务的创建了,按照上述的代码流程,则:
事务的获取,返回的结果不为null
的前提是什么?是当前线程的事务已经存在了。那么事务的构建流程这里想必是没有展开。那么我们来看下第四步,关于事务的构建代码:
public abstract class AbstractPlatformTransactionManager implements PlatformTransactionManager, Serializable {
startTransaction(def, transaction, debugEnabled, suspendedResources);
private TransactionStatus startTransaction(TransactionDefinition definition, Object transaction,
boolean debugEnabled, @Nullable SuspendedResourcesHolder suspendedResources) {
boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
// 1.构建 DefaultTransactionStatus 实例对象
DefaultTransactionStatus status = newTransactionStatus(
definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
// 2.完善事务信息,包括设置ConnectionHolder。隔离级别、timeout等信息
doBegin(transaction, definition);
// 3.主要将当前的事务信息绑定到当前线程的ThreadLocal中
prepareSynchronization(status, definition);
return status;
}
}
我们来看下第二步,事务信息的完善处理:
@Override
protected void doBegin(Object transaction, TransactionDefinition definition) {
DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
Connection con = null;
try {
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());
// 自动提交的设置,由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()) {
// 将当前获取到的连接绑定到当前线程
TransactionSynchronizationManager.bindResource(obtainDataSource(), txObject.getConnectionHolder());
}
}
// ...省略
}
我们在这段代码中发现了Spring开始尝试对数据库连接的获取,也因此我们可以说事务是从这个函数开始的。 这段代码的主要工作:
connectionHolder
绑定到当前线程。到这里为止,讲的内容都是围绕着新建事务的创建过程来展开的,总体可以分为三步:
我们知道,Spring中事务的类型有这么几种:
PROPAGATION_REQUIRED
:支持当前事务,如果当前没有事务,就新建一个事务。PROPAGATION_SUPPORTS
:支持当前事务,如果当前没有事务,就以非事务方式执行。PROPAGATION_MANDATORY
:支持当前事务,如果当前没有事务,就抛出异常。PROPAGATION_REQUIRES_NEW
:新建事务,如果当前存在事务,把当前事务挂起。PROPAGATION_NOT_SUPPORTED
:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。PROPAGATION_NEVER
:以非事务方式执行,如果当前存在事务,则抛出异常。PROPAGATION_NESTED
:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,就新建一个事务。那么如同PROPAGATION_REQUIRES_NEW
和PROPAGATION_NESTED
等类型,Spring又是如何处理的呢?还记得getTransaction
函数中的这段代码吗?
return handleExistingTransaction(def, transaction, debugEnabled);
我们来分析下,对于已经存在的事务,Spring是如何处理的(而这段代码诠释了Spring事务类型对应的语义):
private TransactionStatus handleExistingTransaction(
TransactionDefinition definition, Object transaction, boolean debugEnabled)
throws TransactionException {
// ...省略
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 {
// 重新进行事务的构建
return startTransaction(definition, transaction, debugEnabled, suspendedResources);
}
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() + "]");
}
// 若没有可以使用保存点的方式控制事务的回滚,那么在嵌套事务的简历初始化阶段,创建一个保存点
if (useSavepointForNestedTransaction()) {
DefaultTransactionStatus status =
prepareTransactionStatus(definition, transaction, false, false, debugEnabled, null);
status.createAndHoldSavepoint();
return status;
}
else {
// 类似于JTA这类情况是不能够使用保存点操作的,因此建立新的事务
return startTransaction(definition, transaction, debugEnabled, null);
}
}
// ...省略
boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
return prepareTransactionStatus(definition, transaction, false, newSynchronization, debugEnabled, null);
}
如果事务期间,发生了特定的错误,那么事务将会进行回滚,那么Spring是怎么对数据进行修复的呢?
completeTransactionAfterThrowing(txInfo, ex);
↓↓↓↓↓↓
protected void completeTransactionAfterThrowing(@Nullable TransactionInfo txInfo, Throwable ex) {
// 1.当抛出异常的时候,应该先判断当前是否存在事务(前提,毕竟没有事务,我回滚的意义是啥?)
if (txInfo != null && txInfo.getTransactionStatus() != null) {
if (logger.isTraceEnabled()) {
logger.trace("Completing transaction for [" + txInfo.getJoinpointIdentification() +
"] after exception: " + ex);
}
// 判断 是否进行默认的回滚。 依据:抛出的异常是否为RuntimeException或者Error类型
if (txInfo.transactionAttribute != null && txInfo.transactionAttribute.rollbackOn(ex)) {
try {
// 根据TransactionStatus信息进行回滚处理
txInfo.getTransactionManager().rollback(txInfo.getTransactionStatus());
}
// ..catch
}
else {
// 若不满足回滚条件,即使抛出异常了,也进行提交
try {
txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());
}
// ..catch
}
}
}
我们来看下rollbackOn
函数:
public class DefaultTransactionAttribute extends DefaultTransactionDefinition implements TransactionAttribute {
@Override
public boolean rollbackOn(Throwable ex) {
return (ex instanceof RuntimeException || ex instanceof Error);
}
}
也因此在事务案例章节中,我们手动抛出了个RuntimeException
异常,目的就是触发事务的回滚操作。
当然,若希望回滚触发的异常条件做出改变怎么办?很简单,在注解中添加对应的属性即可,如:
@Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
言归正传,我们需要关注Spring是如何进行回滚的,那么关键的我们来看第二步:
txInfo.getTransactionManager().rollback(txInfo.getTransactionStatus());
↓↓↓↓↓↓
public abstract class AbstractPlatformTransactionManager implements PlatformTransactionManager, Serializable {
@Override
public final void rollback(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;
processRollback(defStatus, false);
}
↓↓↓↓↓↓
private void processRollback(DefaultTransactionStatus status, boolean unexpected) {
try {
boolean unexpectedRollback = unexpected;
try {
// 1.激活所有的 TransactionSynchronization(自定义触发器) 中对应的方法
triggerBeforeCompletion(status);
// 2.若有保存点,那么当前线程的事务会退到保存点
if (status.hasSavepoint()) {
if (status.isDebug()) {
logger.debug("Rolling back transaction to savepoint");
}
status.rollbackToHeldSavepoint();
}
// 3.若当前事务为独立的新事务,则直接返回
else if (status.isNewTransaction()) {
if (status.isDebug()) {
logger.debug("Initiating transaction rollback");
}
doRollback(status);
}
else {
// 4.若当前事务不是独立的事务,那么只能标记状态,等到事务链执行完毕后统一回滚
if (status.hasTransaction()) {
if (status.isLocalRollbackOnly() || isGlobalRollbackOnParticipationFailure()) {
if (status.isDebug()) {
logger.debug("Participating transaction failed - marking existing transaction as rollback-only");
}
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()) {
unexpectedRollback = false;
}
}
}
catch (RuntimeException | Error ex) {
triggerAfterCompletion(status, TransactionSynchronization.STATUS_UNKNOWN);
throw ex;
}
// 激活所有的 TransactionSynchronization(自定义触发器) 中对应的方法
triggerAfterCompletion(status, TransactionSynchronization.STATUS_ROLLED_BACK);
// 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 {
// 清空记录的资源并将挂起的资源恢复
cleanupAfterCompletion(status);
}
}
}
可见回滚操作主要做了这么几个重要的事情:
从上述代码的函数名称上,我们可以主要看rollbackToHeldSavepoint
这个函数:
status.rollbackToHeldSavepoint();
↓↓↓↓↓
public void rollbackToHeldSavepoint() throws TransactionException {
Object savepoint = getSavepoint();
if (savepoint == null) {
throw new TransactionUsageException(
"Cannot roll back to savepoint - no savepoint associated with current transaction");
}
// 通过事务管理器,将程序回滚至指定的保存点
getSavepointManager().rollbackToSavepoint(savepoint);
// 通过事务管理器,释放保存点
getSavepointManager().releaseSavepoint(savepoint);
setSavepoint(null);
}
rollbackToSavepoint
接口有三种实现,这里我们主要看JdbcTransactionObjectSupport
因为我们使用的是JDBC
的方式进行数据库连接,
public abstract class JdbcTransactionObjectSupport implements SavepointManager, SmartTransactionObject {
@Override
public void rollbackToSavepoint(Object savepoint) throws TransactionException {
ConnectionHolder conHolder = getConnectionHolderForSavepoint();
try {
conHolder.getConnection().rollback((Savepoint) savepoint);
conHolder.resetRollbackOnly();
}
catch (Throwable ex) {
throw new TransactionSystemException("Could not roll back to JDBC savepoint", ex);
}
}
}
此时rollback
又有多种实现:
此时我们关注第一个实现类ConnectionImpl
备注:
ConnectionImpl
是Connection
接口的一个实现类,而本案例当中,由于我引入了pom依赖mysql-connector-java
,因此这里走的是ConnectionImpl.rollback()
函数,不同的实现类有着不同的回滚逻辑。这里就不做展开了,主要通过一个保存点案例带大家过一遍用法。
读者请在第一章节的案例基础上进行更改,UserServiceImpl
类:
@Override
public void insert(User user) throws Exception {
DefaultTransactionStatus transactionStatus = (DefaultTransactionStatus) TransactionAspectSupport.currentTransactionStatus();
// 保存点1
transactionStatus.createAndHoldSavepoint();
jdbcTemplate.update("insert into user(id,name,age) values(?,?,?)",
new Object[]{user.getId(), user.getName(), user.getAge()},
new int[]{Types.INTEGER, Types.VARCHAR, Types.INTEGER});
// 保存点2
// transactionStatus.createAndHoldSavepoint();
jdbcTemplate.update("insert into user(id,name,age) values(?,?,?)",
new Object[]{user.getId() + 1, "Hello", 100},
new int[]{Types.INTEGER, Types.VARCHAR, Types.INTEGER});
// 保存点3
// transactionStatus.createAndHoldSavepoint();
throw new RuntimeException("事务测试");
}
执行代码后,分三种情况:
可见默认情况下,回滚将回到最后一个保存点所在的位置。
若不带保存点,那么将走doRollback()
函数:
doRollback(status);
↓↓↓↓↓↓↓
public class DataSourceTransactionManager extends AbstractPlatformTransactionManager implements ResourceTransactionManager, InitializingBean {
protected void doRollback(DefaultTransactionStatus status) {
DataSourceTransactionManager.DataSourceTransactionObject txObject = (DataSourceTransactionManager.DataSourceTransactionObject)status.getTransaction();
// 获取数据库连接
Connection con = txObject.getConnectionHolder().getConnection();
if (status.isDebug()) {
this.logger.debug("Rolling back JDBC transaction on Connection [" + con + "]");
}
try {
// 交给数据库来进行回滚
con.rollback();
} catch (SQLException var5) {
throw new TransactionSystemException("Could not roll back JDBC transaction", var5);
}
}
}
这部分代码比较通俗易懂,就是将回滚的任务委派给数据库本身来执行。而本篇文章主要讲Spring事务的实现机制,因此这里不再赘述(后期准备对数据库进行复习,然后回滚也会做详细的展开)。
回滚逻辑执行结束之后,无论回滚操作是否成功,我们都需要做后续的收尾工作,我们来看下代码:
cleanupAfterCompletion(status);
↓↓↓↓↓↓
private void cleanupAfterCompletion(DefaultTransactionStatus status) {
// 1.设置事务的状态置为完成,目的是为了避免重复调用
status.setCompleted();
// 2.若当前事务是新的同步状态,那么需要将 绑定到当前线程的事务信息清除
if (status.isNewSynchronization()) {
TransactionSynchronizationManager.clear();
}
// 3.如果是新事务,那么需要做一些资源的清除工作
if (status.isNewTransaction()) {
doCleanupAfterCompletion(status.getTransaction());
}
// 4.若事务执行前,还存在挂起的事务,那么当前事务执行结束后,恢复挂起的事务
if (status.getSuspendedResources() != null) {
if (status.isDebug()) {
logger.debug("Resuming suspended transaction after completion of inner transaction");
}
Object transaction = (status.hasTransaction() ? status.getTransaction() : null);
resume(transaction, (SuspendedResourcesHolder) status.getSuspendedResources());
}
}
我们来看下资源清除工作做了些什么操作:
// 接口,具体实现交给子类
doCleanupAfterCompletion(status.getTransaction());
↓↓↓↓↓↓
public class DataSourceTransactionManager extends AbstractPlatformTransactionManager
implements ResourceTransactionManager, InitializingBean {
@Override
protected void doCleanupAfterCompletion(Object transaction) {
DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
// 1.将数据库连接从当前线程中解除绑定
if (txObject.isNewConnectionHolder()) {
TransactionSynchronizationManager.unbindResource(obtainDataSource());
}
// 2.释放连接
Connection con = txObject.getConnectionHolder().getConnection();
try {
// 3.恢复数据库连接的自动提交属性(之前设置事务的时候,是将其交给了Spring来控制)
if (txObject.isMustRestoreAutoCommit()) {
con.setAutoCommit(true);
}
// 4.重置数据库连接
DataSourceUtils.resetConnectionAfterTransaction(
con, txObject.getPreviousIsolationLevel(), txObject.isReadOnly());
}
catch (Throwable ex) {
logger.debug("Could not reset JDBC Connection after transaction", ex);
}
// 5.若当前事务是新创建的事务,那么在事务完成的时候,释放数据库连接
if (txObject.isNewConnectionHolder()) {
if (logger.isDebugEnabled()) {
logger.debug("Releasing JDBC Connection [" + con + "] after transaction");
}
DataSourceUtils.releaseConnection(con, this.dataSource);
}
txObject.getConnectionHolder().clear();
}
}
总结下就是:
最后,回滚操作到这这里也结束了(若出现异常的情况下)。无论程序是走了回滚操作还是正常执行。最后必定会将事务进行提交,只有事务提交上去,程序才算真正的跑完。
我们来看下源码:
public abstract class TransactionAspectSupport implements BeanFactoryAware, InitializingBean {
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());
}
}
}
↓↓↓↓↓↓commit↓↓↓↓↓↓
public abstract class AbstractPlatformTransactionManager implements PlatformTransactionManager, Serializable {
@Override
public final void commit(TransactionStatus status) throws TransactionException {
// 1.事务已经提交完成了,那么这里肯定不能重复提交,抛出异常
if (status.isCompleted()) {
throw new IllegalTransactionStateException(
"Transaction is already completed - do not call commit or rollback more than once per transaction");
}
// 2.若事务已经被标记回滚,那么不能够尝试提交事务,直接回滚
DefaultTransactionStatus defStatus = (DefaultTransactionStatus) status;
if (defStatus.isLocalRollbackOnly()) {
if (defStatus.isDebug()) {
logger.debug("Transactional code has requested rollback");
}
processRollback(defStatus, false);
return;
}
// 同上
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);
}
↓↓↓↓↓↓processCommit↓↓↓↓↓↓
private void processCommit(DefaultTransactionStatus status) throws TransactionException {
try {
boolean beforeCompletionInvoked = false;
try {
boolean unexpectedRollback = false;
prepareForCommit(status);
// 添加 TransactionSynchronization 中对应方法的前后调用
triggerBeforeCommit(status);
triggerBeforeCompletion(status);
beforeCompletionInvoked = true;
// 若存在保存点,则清除保存点信息(事务提交了,保存点存在的意义也就没了)
if (status.hasSavepoint()) {
if (status.isDebug()) {
logger.debug("Releasing transaction savepoint");
}
unexpectedRollback = status.isGlobalRollbackOnly();
status.releaseHeldSavepoint();
}
// 若没有保存点,是个独立的新事务,那么直接提交即可
else if (status.isNewTransaction()) {
if (status.isDebug()) {
logger.debug("Initiating transaction commit");
}
unexpectedRollback = status.isGlobalRollbackOnly();
// 将事务提交的操作委派给数据库来进行
doCommit(status);
}
else if (isFailEarlyOnGlobalRollbackOnly()) {
unexpectedRollback = status.isGlobalRollbackOnly();
}
// Throw UnexpectedRollbackException if we have a global rollback-only
// marker but still didn't get a corresponding exception from commit.
if (unexpectedRollback) {
throw new UnexpectedRollbackException(
"Transaction silently rolled back because it has been marked as rollback-only");
}
}
// ..catch
catch (RuntimeException | Error ex) {
if (!beforeCompletionInvoked) {
triggerBeforeCompletion(status);
}
// 提交过程中出现异常,回滚
doRollbackOnCommitException(status, ex);
throw ex;
}
try {
triggerAfterCommit(status);
}
finally {
triggerAfterCompletion(status, TransactionSynchronization.STATUS_COMMITTED);
}
}
finally {
cleanupAfterCompletion(status);
}
}
}
从上述代码可以发现,即使事务的整个过程到达了最后的提交阶段,但也并不是无脑直接提交的。而是考虑了很多方面:
上述第二点的目的是什么?
若正常提交的时候,根据上述代码进行doCommit
操作,而这里同理事务的回滚(不带保存点),执行逻辑交给数据库连接的API
来执行:
public class DataSourceTransactionManager extends AbstractPlatformTransactionManager
implements ResourceTransactionManager, InitializingBean {
@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);
}
}
}
到这里事务的整套流程也就完成了,接下来放流程图做总结。