尧图网站建设 尧图网络
  • 首页
  • 关于我们
  • 服务项目
  • 案例展示
  • 建站流程
  • 资讯中心
  • 联系我们
首页/资讯中心/详情

Spring 事务 - 实践

Spring 事务 - 实践
📅 发布时间:2026/6/19 12:52:40

目录

前言

一、事务

1. 事务的概念

2. Spring 中的事务

1. 编程式事务

2. 声明式事务

二、 @Transactional

1. rollbackFor

2. isolation

3. Spring 事务的传播机制

4. Spring 事务传播机制演示

1. required

2. requires_new

3. nested

4. required 和 nested 的区别


前言

本文介绍了Spring框架中的事务管理机制。主要内容包括:1. 事务基本概念,即一组操作的原子性执行;2. Spring提供的两种事务实现方式:编程式事务(手动管理)和声明式事务(通过@Transactional注解);3. @Transactional注解的核心属性:rollbackFor(异常回滚规则)、isolation(隔离级别)和propagation(传播机制);4. 重点讲解了7种事务传播机制及其应用场景,特别是REQUIRED、REQUIRES_NEW和NESTED的区别。文章通过代码示例展示了不同传播机制下的行为差异,帮助开发者根据业务需求选择合适的事务管理策略。


一、事务

1. 事务的概念

事务是一组操作的集合,是一个不可分割的操作;

事务会把组内的操作视作一个整体,如果所有操作全部成功,事务进行提交,如果有一个或者多个步骤失败,就会将成功的操作也进行回滚,实现整体上全部成功,或者全部不成功的功能;

事务的操作有 3 个步骤:

  • 1. 开启事务;
  • 2. 提交事务;
  • 3. 回滚事务;

2. Spring 中的事务

Spring 中的事务操作分为两类:

  • 编程式事务:手动编程,操作事务;
  • 声明式事务:利用注解,自动开启,提交或者回滚事务;

1. 编程式事务

DataSourceTransactionManager:事务管理器,用来获取事务,开启事务,提交事务,回滚事务;

TransactionDefinition:事务的属性,在获取事务的时候,将 TransactionDefinition 传递进去,从而获得一个事务 TransactionStatus;

手动实现事务的提交和回滚:

package com.example.trans.controller;
import com.example.trans.service.UserInfoService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@Slf4j
@RestController
@RequestMapping("/user")
public class UserInfoController {@Autowiredprivate DataSourceTransactionManager dataSourceTransactionManager;@Autowiredprivate TransactionDefinition transactionDefinition;@Autowiredprivate UserInfoService userInfoService;@RequestMapping("/register")public Boolean register(String userName, String password){// 1. 参数校验log.info("/user/register接收到参数:userName: {}, password: {}", userName, password);if(!StringUtils.hasLength("userName") || !StringUtils.hasLength(password)){return false;}// 2. 开启事务TransactionStatus transactionStatus = dataSourceTransactionManager.getTransaction(transactionDefinition);// 3. 调用 servicetry{Integer result = userInfoService.insertUserInfo(userName, password);if(result <= 0){return false;}}catch (Exception e){return false;}// 4. 提交事务
//        dataSourceTransactionManager.commit(transactionStatus);// 5. 回滚事务dataSourceTransactionManager.rollback(transactionStatus);return true;}
}

2. 声明式事务

使用  @Transactional 注解,自动实现事务的开启,提交和回滚;

package com.example.trans.controller;
import com.example.trans.service.UserInfoService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.io.IOException;
@Slf4j
@RestController
@RequestMapping("/user2")
public class UserInfoController2 {@Autowiredprivate UserInfoService userInfoService;// @Transactional 自动实现事务的开启,提交或者回滚@Transactional@RequestMapping("/register")public Boolean register(String userName, String password) throws IOException {// 1. 参数校验log.info("/user/register接收到参数:userName: {}, password: {}", userName, password);if(!StringUtils.hasLength("userName") || !StringUtils.hasLength(password)){return false;}// 2. 调用 servicetry{Integer result = userInfoService.insertUserInfo(userName, password);int n = 10 / 0;if(result <= 0){return false;}}catch (Exception e){// 手动回滚TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
//            return false;}return true;}
}

 @Transactional 可以用来修饰方法和类:

  • 修饰方法时,只有修饰被 public 修饰的方法才生效;
  • 修饰类时,对类中的所有被 public 修饰的方法生效;

事务提交和回滚的情况分析:

当所有操作执行成功,事务提交;

当发生运行时异常或者错误时,且异常没有被捕获,事务会自动回滚;

如果发生运行时异常且异常被捕获,则事务提交;

如果发生的是受查异常,则事务会提交;

如果发生运行时异常后,捕获到了异常,仍然想要实现回滚:可以再次抛出异常,也可以手动回滚;

如果发生的是受查异常,仍然想要回滚,可以设置 @Transactional 的属性 rollbackFor 为 Exception.class 类型;

二、 @Transactional

@Transactional 常见的三个属性:

rollbackFor:异常回滚属性,能够指定多个异常类型,发生指定类型的异常时,事务会实现回滚;

Isolation:事务的隔离级别;

propagation:事务的传播机制;

1. rollbackFor

package com.example.trans.controller;
import com.example.trans.service.UserInfoService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.io.IOException;
@Slf4j
@RestController
@RequestMapping("/user2")
public class UserInfoController2 {@Autowiredprivate UserInfoService userInfoService;// @Transactional 自动实现事务的开启,提交或者回滚@Transactional(rollbackFor = Exception.class)@RequestMapping("/register")public Boolean register(String userName, String password) throws IOException {// 1. 参数校验log.info("/user/register接收到参数:userName: {}, password: {}", userName, password);if(!StringUtils.hasLength("userName") || !StringUtils.hasLength(password)){return false;}// 2. 调用 servicetry{Integer result = userInfoService.insertUserInfo(userName, password);int n = 10 / 0;if(result <= 0){return false;}}catch (Exception e){throw new IOException();}return true;}
}

设置 rollbackFor 的类型为 Exception.class 后,只要发生异常,就会实现回滚;

2. isolation

MySQL 有 4 种隔离级别,分别是:读未提交,读已提交,可重复度和串行化;

读未提交:事务 A 写数据时,事务 B 可以读到,如果事务 A 之后又修改了数据,事务 B 读到的就是脏数据,也称为脏读;

读已提交:当事务 A 提交后,事务 B 能读到,事务 C 又修改了当初事务 A 提交的数据,此时事务 B 再读,发现数据前后不一致了,称为不可重复读;

可重复读:当事务 A 提交后,事务 B 不能读到事务 A 产生的数据,但是当 事务 B 想要插入数据时,发现数据行的 ID 已经被占用,事务 B 能感知到数据发生变化,但是读不到,称为幻读;

串行化: 把事务进行排序,一个一个执行,完全没有并发;

MySQL 的默认隔离界别时可重复读;Spring 的默认隔离级别是采用数据库设置的隔离级别;

package org.springframework.transaction.annotation;
public enum Isolation {DEFAULT(-1),READ_UNCOMMITTED(1),READ_COMMITTED(2),REPEATABLE_READ(4),SERIALIZABLE(8);private final int value;private Isolation(int value) {this.value = value;}public int value() {return this.value;}
}

3. Spring 事务的传播机制

传播机制:当多个事务方法存在调用关系,事务在这些方法的传播方式;

事务的隔离机制解决的是多个事务同时调用一个数据的问题;

事务的传播机制解决的是一个事务在多个方法中传递的问题;

@Transactional 可以设置 propagation 属性,设置事务的传播机制;

传播机制有 7 种:

package org.springframework.transaction.annotation;
public enum Propagation {REQUIRED(0),SUPPORTS(1),MANDATORY(2),REQUIRES_NEW(3),NOT_SUPPORTED(4),NEVER(5),NESTED(6);private final int value;private Propagation(int value) {this.value = value;}public int value() {return this.value;}
}

Propagation.REQUIRED:默认事务传播级别,如果当前存在事务,则加入该事务,如果当前不存在事务,则创建一个新的事务;

Propagation.REQUIRES_NEW:不管当前是否存在事务(如果有事务则挂起),都要创建一个新的事务;

Propagation.NESTED:如果当前存在一个事务,则创建一个新的事务,作为嵌套事务运行,如果嵌套事务发生异常,且异常被 catch 住了,则不影响原有事务,如果当前不存在事务,则创建一个新的事务运行;

Propagation.SUPPORTS:如果当前存在事务,则加入该事务,如果当前不存在事务,则以非事务的方式运行;

Propagation.NOT_SUPPORTED:如果当前存在事务,则挂起,以非事务的方式运行;

Propagation.MANDATORY:如果当前不存在事务,则抛出异常;

Propagation.NEVER:如果当前存在事务,则抛出异常;

4. Spring 事务传播机制演示

1. required

用户注册接口:

package com.example.trans.controller;
import com.example.trans.service.LogInfoService;
import com.example.trans.service.UserInfoService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.io.IOException;
@Slf4j
@RestController
@RequestMapping("/user2")
public class UserInfoController2 {@Autowiredprivate UserInfoService userInfoService;@Autowiredprivate LogInfoService logInfoService;// @Transactional 自动实现事务的开启,提交或者回滚@Transactional(rollbackFor = Exception.class, isolation = Isolation.REPEATABLE_READ)@RequestMapping("/register")public Boolean register(String userName, String password) throws IOException {// 1. 参数校验log.info("/user/register接收到参数:userName: {}, password: {}", userName, password);if(!StringUtils.hasLength("userName") || !StringUtils.hasLength(password)){return false;}// 2. 调用 servicetry{Integer result = userInfoService.insertUserInfo(userName, password);Integer result2 = logInfoService.insertLogInfo(userName, "用户注册");if(result <= 0 || result2 <= 0){return false;}}catch (Exception e){// 手动回滚TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();}return true;}
}

UserInfoService:

package com.example.trans.service;
import com.example.trans.mapper.UserInfoMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
@Service
public class UserInfoService {@Autowiredprivate UserInfoMapper userInfoMapper;@Transactional(propagation = Propagation.REQUIRED)public Integer insertUserInfo(String userName, String password) {return userInfoMapper.insertUserInfo(userName, password);}
}

LogInfoService:

package com.example.trans.service;
import com.example.trans.mapper.LogInfoMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
@Service
public class LogInfoService {@Autowiredprivate LogInfoMapper logInfoMapper;@Transactional(propagation = Propagation.REQUIRED)public Integer insertLogInfo(String userName, String op) {return logInfoMapper.insertLogInfo(userName, op);}
}

成功运行时:

LogInfoService 抛出异常:事务不会被提交

package com.example.trans.service;
import com.example.trans.mapper.LogInfoMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
@Service
public class LogInfoService {@Autowiredprivate LogInfoMapper logInfoMapper;@Transactional(propagation = Propagation.REQUIRED)public Integer insertLogInfo(String userName, String op) {int n = 10 / 0;return logInfoMapper.insertLogInfo(userName, op);}
}

2. requires_new

 注册接口代码不变,更改 UserInfoService 和 LogInfoService 的传播机制为 requires_new:

UserInfo 提交成功,LogInfo 没有提交;

3. nested

注册接口代码不变,更改 UserInfoService 和 LogInfoService 的传播机制为 nested;

捕获 LogInfoService 中的异常,并手动回滚事务:

package com.example.trans.service;
import com.example.trans.mapper.LogInfoMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
@Service
public class LogInfoService {@Autowiredprivate LogInfoMapper logInfoMapper;@Transactional(propagation = Propagation.NESTED)public Integer insertLogInfo(String userName, String op) {try{int n = 10 / 0;}catch(Exception e){// 手动回滚TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();}return logInfoMapper.insertLogInfo(userName, op);}
}

测试:事务提交,LogInfo 实现了手动回滚;

4. required 和 nested 的区别

如果事务全部执行成功,二者是相同的;

如果事务一部分执行成功,required 加入事务会使整个事务全部回滚,nested 如果 catch 住异常,能手动实现部分回滚,不影响整个事务的提交;


相关新闻

  • Spring AI Alibaba 项目源码学习(二)-Graph 定义与描述分析
  • 20232422 2024-2025-1 《网络与系统攻防技术》实验四实验报告
  • SPI 设备与多从机冲突的解决之道:片选管理、CS 去抖与总线隔离策略 - 实践

最新新闻

  • 按摩椅双推杆泰式拉筋与普通拉伸效果差异先对照推杆行程与拉伸角度 - 新闻快传
  • 深入解析UART异步串行通信:从分数分频器到硬件流控制
  • 考研政治网课哪家押题准? - 新闻快传
  • Gemini 3多模态系统级协同:视觉定位、跨模态对齐与工具内生化
  • ClaudeCode开源解析:多模态AI Agent如何实现真实电脑操作
  • 2026昭通2026正规漏水检测维修公司精选口碑榜TOP5权威推荐-精准定位检测漏水点-专业防水补漏堵漏维修、卫生间/厨房/屋顶/天沟/地下室/阳台防水漏水检测维修 - 安佳防水

日新闻

  • 5分钟掌握Python进化算法:Geatpy高性能优化工具完全指南
  • Microchip 24AA044 EEPROM选型与应用全指南:从参数解析到实战编程
  • 华为的鸿蒙到底有多牛?为什么称作遥遥领先?

周新闻

  • 3步解锁iOS设备:applera1n激活锁绕过完全指南
  • 39 2026 人工智能证书终极盘点,普通人选 AI 证书可以从这些方向入手
  • Redis 暴露公网有多危险?从端口检查到补救步骤

月新闻

  • 【总结】入门篇:50句话让你记住架构核心概念
  • WeChatMsg技术方案解析:实现Mac微信数据自主管理的完整解决方案
  • WeChatMsg:革新性微信数据备份方案,打造你的专属数字记忆库

关于尧图

  • 公司简介
  • 团队介绍
  • 企业文化
  • 荣誉资质

服务项目

  • 定制开发
  • 电商建站
  • UI 设计
  • 运维服务

快速链接

  • 案例展示
  • 建站流程
  • 常见问题
  • 资讯中心

联系方式

  • 📍北京市朝阳区互联网产业园 A 座 10 层
  • 📞400-888-8888
  • ✉️contact@rkmt.cn
  • 🕐周一至周日 9:00-21:00

© 2024 北京尧图网络科技有限公司 版权所有 | 京 ICP 备 XXXXXXXX 号