Spring学习-事务

📅 2026/7/30 2:45:13 👁️ 阅读次数 📝 编程学习
Spring学习-事务

一、数据库事务的基本特性

1.事物的基本特性

  • 原子性
  • 一致性
  • 隔离性
  • 持久性

2.事务的隔离级别

隔离级别 脏读 不可重复读 幻读
读未提交 可能 可能 可能
读已提交 不可能 可能 可能
可重复读 不可能 不可能 可能
串行化 不可能 不可能 不可能
  • 脏读:在一个事务中读取到了其它事务未提交的数据
  • 不可重复读:在一个事务中,两次读取结果不一样
  • 幻读: 先判断身份证号是否存在再插入数据的情况,在高并发下会出现同时插入两条相同的身份证号

二、Spring 对事务的支持与适用

1.Spring 事务相关API说明

spring 事务是在数据库事务的基础上进行封装拓展

  • 支持原有的事务隔离级别
  • 加入了事务传播的概念,提供多个事务的合并或隔离的功能
  • 提供声明式事务,让业务代码与事务分离,事务变得更易用

spring 提供了三个接口供事务使用

  • TransactionDefinition:事务定义
  • PlatformTransactionManager: 事务管理
  • TransactionStatus: 事务运行时状态

2.声明式事务

@Transactional

3.事务的传播机制

类别 事务传播类型 说明
支持当前事务 PROPAGATION_REQUIRED(必须的) 如果当前没有事务,就新建一个事务,如果已经存在一个事务,加入到这个事务中。
支持当前事务 PROPAGATION_SUPPORT(支持) 支持当前事务,如果当前没有事务,就以非事务方式执行
支持当前事务 PROPAGATION_MANDATORY(强制) 使用当前的事务,如果当前没有事务就抛出异常
不支持当前事务 PROPAGATION_REQUIRED_NEW(隔离) 新建事务,如果当前存在事务,把当前事务挂起
不支持当前事务 PROPAGATION_NOT_SUPPORTED(不支持) 以非事务方式进行操作,如果当前存在事务,就把当前事务挂起
不支持当前事务 PROPAGATION_NEVER(强制非事务) 以非事务方式执行,如果当前存在事务,则抛出异常
套事务 PROPAGATION_NESTED(强制非事务) 以非事务方式执行,如果当前存在事务,则抛出异常

常用事务传播机制

  • PROPAGATION_REQUIRED:这个也是默认的事务传播机制
  • PROPAGATION_NOT_SUPPORTED:可以用于发送提示消息、站内信、短信、邮件提示等。不属于并且不应当影响主体业务逻辑,即使发送失败也不应该对主体业务逻辑回滚
  • PROPAGATION_REQUIRED_NEW:总是新启一个事务,这个传播机制适用于不受父方法事务影响的操作,比如某个业务场景下需要记录业务日志,用于异步反查,那么不管主体业务逻辑是否完成,日志都需要记录下来,不能因为主体业务逻辑报错而丢失日志

案例一

创建用户时初始化一个账户,表结构和服务类如下

表结构 服务类 功能描述
user UserServcie 创建用户,并添加账户
account AccountService 添加账户

UserService.createUser(name)伪代码

 @Transactionalpublic void createUser(String name) {// 新增用户基本信息jdbcTemplate.update("insert into `user` (name) values(?)", name);// 调用accountService添加账户acccoutService.addAccount(name, 10000);
}

acccoutService.addAccount(name,initMoney)

@Transactional(propagation = Propagation.REQUIRED)
public void addAccount(String name, int initMoney) {String accountId = String.valueOf(System.currentTimeMillis());jdbcTemplate.update("insert into `account` (account_name,user,money) values(?, ?, ?)", accountId, name, initMoney);// 分母为0异常int i = 1 / 0;
}

预测

createUser addAccount 结果
场景一 无事务 required(假定有异常) user添加成功,account添加失败
场景二 required 无事务(假定有异常) user添加失败,account添加失败(addAccount无事务,使用createUser的事务)
场景三 required not_supported(假定有异常) user添加是失败,account添加成功(addAccount事务挂起添加成功,存在报错影响createUser,故user添加失败)
场景四 required required_new(假定有异常) user添加失败,account添加失败
场景五 required(假定有异常) required_new user添加失败,account添加成功(account 独立事务添加成功)

三、aop 事务底层实现原理

spring 声明式事务使用动态代理实现,当调用同一个类的方法时,是不会走代理逻辑的,因此事务会失效

// TransactionInterceptor 核心逻辑
public Object invoke(MethodInvocation invocation) throws Throwable {// 1. 获取事务属性(@Transactional 配置)TransactionAttribute txAttr = getTransactionAttributeSource().getTransactionAttribute(method, targetClass);// 2. 获取 PlatformTransactionManagerPlatformTransactionManager tm = getTransactionManager(txAttr);// 3. 创建事务信息TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);try {// 4. 执行目标方法Object retVal = invocation.proceed();// 5. 提交事务commitTransactionAfterReturning(txInfo);return retVal;} catch (Throwable ex) {// 6. 异常回滚completeTransactionAfterThrowing(txInfo, ex);throw ex;} finally {// 7. 清理事务信息cleanupTransactionInfo(txInfo);}
}