当前位置: 首页 > web >正文

Spring 学习笔记之 @Transactinal实现原理

Spring 框架中的@Transactional注解是用来简化数据库事务管理的重要工具。下面详细介绍它实现数据库事务的原理。

核心原理概述

@Transactional主要借助 Spring 的 AOP(面向切面编程)机制来达成事务管理。当一个方法被@Transactional注解修饰时,Spring 会在该方法执行前后添加事务相关的处理逻辑,以保证方法内的数据库操作在一个统一的事务环境中进行。

具体实现步骤

1. 配置事务管理器

在 Spring 应用里,你得先配置一个事务管理器,这个管理器会和具体的数据源关联起来。例如,使用DataSourceTransactionManager管理基于 JDBC 的事务。以下是 Java 配置示例:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import javax.sql.DataSource;@Configuration
public class TransactionConfig {@Beanpublic PlatformTransactionManager transactionManager(DataSource dataSource) {return new DataSourceTransactionManager(dataSource);}
}

2. 启用事务注解支持

在 Spring 配置类上添加@EnableTransactionManagement注解,以此开启@Transactional注解的功能。

import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.annotation.EnableTransactionManagement;@Configuration
@EnableTransactionManagement
public class AppConfig {// 其他配置
}

@EnableTransactionManagement 注解的作用就是开启这种声明式事务管理功能。

注解属性

  • mode:用于指定 AOP 代理模式,有 AdviceMode.PROXY(默认值,使用 Spring AOP 代理)和 AdviceMode.ASPECTJ(使用 AspectJ 进行切面织入)两种可选值。
  • proxyTargetClass:仅在 mode 为 AdviceMode.PROXY 时有效,若为 true 则使用 CGLIB 代理,为 false 则使用 JDK 动态代理。
  • order:指定事务增强器的执行顺序。

工作流程

  • 导入配置类:@EnableTransactionManagement 注解借助 @Import 注解导入 TransactionManagementConfigurationSelector 类。

  • 配置类选择:TransactionManagementConfigurationSelector 会依据 AOP 代理模式来选择配置类。若使用 JDK 动态代理,就导入 ProxyTransactionManagementConfiguration 类;若使用 CGLIB 代理,则导入 AspectJTransactionManagementConfiguration 类。

  • 注册事务增强器:所选的配置类会注册 BeanFactoryTransactionAttributeSourceAdvisor 事务增强器。这个增强器会扫描带有 @Transactional 注解的方法,为其创建代理对象。

3. AOP 代理创建

当 Spring 容器启动时,它会扫描所有带有@Transactional注解的类和方法,然后借助 AOP 为这些类或方法创建代理对象。Spring 提供了两种代理方式:JDK 动态代理和 CGLIB 代理。

  • JDK 动态代理:若目标对象实现了接口,Spring 默认会使用 JDK 动态代理。
  • CGLIB 代理:若目标对象没有实现接口,Spring 会使用 CGLIB 代理。
     

4. 事务拦截器插入

在代理对象中,Spring 会插入一个事务拦截器(TransactionInterceptor)。这个拦截器会在目标方法执行前后进行事务管理。

@SuppressWarnings("serial")
public class TransactionInterceptor extends TransactionAspectSupport implements MethodInterceptor, Serializable {...@Override@Nullablepublic Object invoke(MethodInvocation invocation) throws Throwable {// Work out the target class: may be {@code null}.// The TransactionAttributeSource should be passed the target class// as well as the method, which may be from an interface.Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);// Adapt to TransactionAspectSupport's invokeWithinTransaction...return invokeWithinTransaction(invocation.getMethod(), targetClass, invocation::proceed);}}

执行拦截器invoke方法的时候,主要业务逻辑在invokeWithTransaction方法里。

5. 事务拦截器工作流程

  • 方法调用:当调用被@Transactional注解修饰的方法时,实际上调用的是代理对象的方法。
  • 事务开启:事务拦截器会根据@Transactional注解的配置,从事务管理器获取一个事务,并开启这个事务。
  • 目标方法执行:在事务开启后,拦截器会调用目标对象的实际方法,执行数据库操作。
  • 事务提交或回滚
    • 正常情况:若目标方法正常执行完毕,没有抛出异常,事务拦截器会提交事务。
    • 异常情况:若目标方法抛出了异常,事务拦截器会根据@Transactional注解的rollbackFornoRollbackFor属性来判断是否需要回滚事务。若需要回滚,就会执行回滚操作。

invokeWithTransaction源代码如下,讲述了事务的具体执行流程。

PlatformTransactionManager ptm = asPlatformTransactionManager(tm);final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);if (txAttr == null || !(ptm instanceof CallbackPreferringPlatformTransactionManager cpptm)) {// Standard transaction demarcation with getTransaction and commit/rollback calls.TransactionInfo txInfo = createTransactionIfNecessary(ptm, txAttr, joinpointIdentification);Object retVal;try {// This is an around advice: Invoke the next interceptor in the chain.// This will normally result in a target object being invoked.retVal = invocation.proceedWithInvocation();}catch (Throwable ex) {// target invocation exceptioncompleteTransactionAfterThrowing(txInfo, ex);throw ex;}finally {cleanupTransactionInfo(txInfo);}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) {Throwable cause = ex.getCause();Assert.state(cause != null, "Cause must not be null");if (txAttr.rollbackOn(cause)) {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);}}}commitTransactionAfterReturning(txInfo);return retVal;}

retVal = invocation.proceedWithInvocation(); 执行原始业务逻辑。

completeTransactionAfterThrowing(txInfo, ex); 处理碰到异常事务回滚。

commitTransactionAfterReturning(txInfo); 正常流程执行完成,提交事务。

示例代码

以下是一个简单的示例,展示如何使用@Transactional注解:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;@Service
public class UserService {@Autowiredprivate UserRepository userRepository;@Transactionalpublic void createUser(User user) {userRepository.save(user);// 可能会抛出异常的代码if (user.getName() == null) {throw new RuntimeException("用户名不能为空");}}
}

在上述示例中,createUser方法被@Transactional注解修饰。若方法执行过程中抛出RuntimeException,事务会回滚,user不会被保存到数据库。

总结

@Transactional注解通过 Spring 的 AOP 机制,在目标方法执行前后插入事务管理逻辑,从而实现了数据库事务的自动管理。它大大简化了事务处理的代码,提升了开发效率。

http://www.xdnf.cn/news/2278.html

相关文章:

  • Loki日志体系的搭建
  • Linux: 如何在VMware上安装Ubuntu操作系统
  • Redis 数据类型全览:特性、场景与操作实例
  • 泽润新能IPO隐忧:募资缩水2亿元,毛利率两连降,内控存瑕疵?
  • Eigen稀疏矩阵类 (SparseMatrix)
  • VS2019 与gitcode团队管理
  • QT6 源(52)篇二:存储 c 语言字符串的类 QByteArray 的使用举例,
  • Git基本操作
  • 第34课 常用快捷操作——按“空格键”旋转图元
  • MySQL技术白皮书
  • 定位与解决线上 OOM 问题:原因分析与快速排查指南
  • o4 - mini 助力,OpenAI 向免费用户推出轻量版 Deep Research
  • CMake 中使用动态库时的 DLL 拷贝逻辑详解(以 zlib 为例)
  • 【BBDM】main.py -- notes
  • 传统智慧焕新,打造现代养生生活
  • X86物理机安装iStoreOS软路由
  • ShaderToy学习笔记 01.基础知识
  • C++学习:六个月从基础到就业——模板编程:函数模板
  • ARP协议【复习篇】
  • 从头训练小模型: 预训练(Pretrain)
  • 财务管理域——绩效管理系统设计
  • 某东h5st_5.1(补环境)
  • 119. 杨辉三角 II
  • C++模拟Java C#的 finally
  • 数据结构顺序表的实现
  • PyTorch作为深度学习框架在建筑行业的应用
  • 从基础到实践(三十三):USB接口简介
  • Python文件操作及数据库交互(Python File Manipulation and Database Interaction)
  • 【刷题Day27】Python/JAVA - 01(浅)
  • 状态压缩DP:蒙德里安的梦想