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

Spring 中事务的实现

1.代码准备

创建数据库:

-- 创建数据库
DROP DATABASE IF EXISTS trans_test;CREATE DATABASE trans_test DEFAULT CHARACTER SET utf8mb4;-- 用户表
DROP TABLE IF EXISTS user_info;
CREATE TABLE user_info (`id` INT NOT NULL AUTO_INCREMENT,`user_name` VARCHAR (128) NOT NULL,`password` VARCHAR (128) NOT NULL,`create_time` DATETIME DEFAULT now(),`update_time` DATETIME DEFAULT now() ON UPDATE now(),PRIMARY KEY (`id`)
) ENGINE = INNODB DEFAULT CHARACTER 
SET = utf8mb4 COMMENT = '用户表';-- 操作日志表
DROP TABLE IF EXISTS log_info;
CREATE TABLE log_info (`id` INT PRIMARY KEY auto_increment,`user_name` VARCHAR ( 128 ) NOT NULL,`op` VARCHAR ( 256 ) NOT NULL,`create_time` DATETIME DEFAULT now(),`update_time` DATETIME DEFAULT now() ON UPDATE now() 
) DEFAULT charset 'utf8mb4';

配置⽂件:

spring:datasource:url: jdbc:mysql://127.0.0.1:3306/trans_test?characterEncoding=utf8&useSSL=falseusername: rootpassword: rootdriver-class-name: com.mysql.cj.jdbc.Drivermybatis:configuration: # 配置打印MyBatis⽇志log-impl: org.apache.ibatis.logging.stdout.StdOutImplmap-underscore-to-camel-case: true #配置驼峰⾃动转换

实体类:

@Service
public class UserService {@Autowiredprivate UserInfoMapper userInfoMapper;public void insertUser(String name,String password){userInfoMapper.insertByUser(name,password);}
}@Service
public class LogService {private LogInfoMapper logInfoMapper;public void insertLog(String name,String op){logInfoMapper.insertLog(name,op);}
}

Mapper:

@Mapper
public interface LogInfoMapper {@Insert("insert into log_info(`user_name`,`op`)values(#{name},#{op})")Integer insertLog(String name,String op);
}@Mapper
public interface UserInfoMapper {@Insert("insert into user_info(`user_name`,`password`)values(#{name},#{password})")Integer insertByUser(String name,String password);
}

Service:

@Service
public class LogService {private LogInfoMapper logInfoMapper;public void insertLog(String name,String op){logInfoMapper.insertLog(name,op);}
}@Service
public class UserService {@Autowiredprivate UserInfoMapper userInfoMapper;public void insertUser(String name,String password){userInfoMapper.insertByUser(name,password);}
}

Controller:

@Slf4j
@RequestMapping("/user")
@RestController
public class UserController {@Autowiredprivate UserService userService;@RequestMapping("/ins")public String insertByUser(String name,String password){if(!StringUtils.hasLength(name) || !StringUtils.hasLength(password)){return "账号为空或密码为空";}userService.insertUser(name,password);log.info("数据插入成功");return "注册成功";}
}

2.Spring声明式事务@Transactional

添加依赖:

 <dependency><groupId>org.springframework</groupId><artifactId>spring-tx</artifactId></dependency>

代码实现:

@Slf4j
@RequestMapping("/user")
@RestController
public class UserController {@Autowiredprivate UserService userService;@Transactional@RequestMapping("/ins")public String insertByUser(String name,String password){if(!StringUtils.hasLength(name) || !StringUtils.hasLength(password)){return "账号为空或密码为空";}userService.insertUser(name,password);log.info("数据插入成功");return "注册成功";}
}

运⾏程序,在postman插入数据,数据插入成功(不具体演示)

修改程序,使之出现异常:

@Slf4j
@RequestMapping("/user")
@RestController
public class UserController {@Autowiredprivate UserService userService;@Transactional@RequestMapping("/ins")public String insertByUser(String name,String password){if(!StringUtils.hasLength(name) || !StringUtils.hasLength(password)){return "账号为空或密码为空";}userService.insertUser(name,password);log.info("数据插入成功");//插入异常int a = 10 / 0;return "注册成功";}
}

运⾏程序:发现虽然⽇志显⽰数据插⼊成功,但数据库却没有新增数据,事务进⾏了回滚

@Transactional 作⽤

  • 修饰⽅法时:只有修饰public⽅法时才⽣效(修饰其他⽅法时不会报错,也不⽣效)
  • 修饰类时:对 @Transactional 修饰的类中所有的public⽅法都⽣效

⽅法/类被 @Transactional 注解修饰时,在⽬标⽅法执⾏开始之前,会⾃动开启事务,⽅法执⾏结束之后,⾃动提交事务

如果在⽅法执⾏过程中,出现异常,且异常未被捕获,就进⾏事务回滚操作

如果异常被程序捕获,⽅法就被认为是成功执⾏,依然会提交事务

如果需要事务进⾏回滚,有以下两种⽅式:

重新抛出异常

@Slf4j
@RequestMapping("/user")
@RestController
public class UserController {@Autowiredprivate UserService userService;@Transactional@RequestMapping("/ins")public String insertByUser(String name,String password){if(!StringUtils.hasLength(name) || !StringUtils.hasLength(password)){return "账号为空或密码为空";}userService.insertUser(name,password);log.info("数据插入成功");//插入异常try {int a = 10 / 0;}catch (Exception e){throw e;}return "注册成功";}
}

⼿动回滚事务

@Slf4j
@RequestMapping("/user")
@RestController
public class UserController {@Autowiredprivate UserService userService;@Transactional@RequestMapping("/ins")public String insertByUser(String name,String password){if(!StringUtils.hasLength(name) || !StringUtils.hasLength(password)){return "账号为空或密码为空";}userService.insertUser(name,password);log.info("数据插入成功");//插入异常try {int a = 10 / 0;}catch (Exception e){TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();}return "注册成功";}
}

3. @Transactional 详解

rollbackFor

异常回滚属性,指定能够触发事务回滚的异常类型,可以指定多个异常类型

@Transactional 默认只在遇到运⾏时异常和Error时才会回滚,⾮运⾏时异常不回滚。即Exception的⼦类中,除了RuntimeException及其⼦类。

接下来我们把异常改为如下代码:

@Slf4j
@RequestMapping("/user")
@RestController
public class UserController {@Autowiredprivate UserService userService;@Transactional@RequestMapping("/ins")public String insertByUser(String name,String password)  throws IOException {if(!StringUtils.hasLength(name) || !StringUtils.hasLength(password)){return "账号为空或密码为空";}userService.insertUser(name,password);log.info("数据插入成功");//插入异常if(true){throw new IOException();}return "注册成功";}
}

运行结果:

我们发现程序抛出了异常,但我们进入数据库中查看数据,数据依然成功添加。

如果我们需要所有异常都回滚,需要来配置过 @Transactional 注解当中的 ollbackFor 这个属性指定出现何种异常类型时事务进⾏回滚

    @Transactional(rollbackFor = Exception.class)

Spring 事务隔离级别

Isolation.DEFAULT :以连接的数据库的事务隔离级别为主

Isolation.READ_UNCOMMITTED :读未提交,对应SQL标准中READ UNCOMMITTED

Isolation.READ_COMMITTED :读已提交,对应SQL标准中 READ COMMITTED

Isolation.REPEATABLE_READ :可重复读,对应SQL标准中 REPEATABLE READ

Isolation.SERIALIZABLE:串行化,对于SQL标准中 SERIALIZABLE

Spring 中事务隔离级别可以通过 @Transactional 中的 isolation 属性进⾏设置

 @Transactional(isolation = Isolation.READ_COMMITTED)

Spring 事务传播机制

Spring 事务传播机制定义了多个事务方法相互调用时,事务如何传播的行为。

通过@Transactional(propagation = Propagation.XXX)注解配置,共有7种传播行为,核心解决事务嵌套或并行执行时的边界问题。

  1. Propagation.REQUIRED :默认的事务传播级别.如果当前存在事务,则加⼊该事务.如果当前没 有事务,则创建⼀个新的事务
  2. Propagation.SUPPORTS :如果当前存在事务,则加⼊该事务.如果当前没有事务,则以⾮事务的 ⽅式继续运⾏
  3. Propagation.MANDATORY :强制性.如果当前存在事务,则加⼊该事务.如果当前没有事务,则 抛出异常
  4. Propagation.REQUIRES_NEW :创建⼀个新的事务.如果当前存在事务,则把当前事务挂起.也 就是说不管外部⽅法是否开启事务, Propagation.REQUIRES_NEW 修饰的内部⽅法都会新开 启⾃⼰的事务,且开启的事务相互独⽴,互不⼲扰
  5. Propagation.NOT_SUPPORTED :以⾮事务⽅式运⾏,如果当前存在事务,则把当前事务挂起(不 ⽤)
  6. Propagation.NEVER :以⾮事务⽅式运⾏,如果当前存在事务,则抛出异常
  7. Propagation.NESTED :如果当前存在事务,则创建⼀个事务作为当前事务的嵌套事务来运⾏. 如果当前没有事务,则该取值等价于 PROPAGATION_REQUIRED 
http://www.dtcms.com/a/434755.html

相关文章:

  • 苏州哪家公司做网站网站布局是什么
  • AI智能体在研究分析中的仿真应用:预测、生存与建构——情绪是基于趋利避害的预测机制吗?
  • 12.排序(上)
  • Java bean 数据校验
  • 级数敛散性判别:泰勒展开与等价无穷小的正确使用
  • gRPC从0到1系列【13】
  • 笔记本 光驱 的内部结构及用法: 应急系统启动 (恢复) 光盘 (DVD+R/RW)
  • DirectX Repair下载安装教程(附安装包)2025最新版(DirectX Repair V4.5增强版+dll修复工具)
  • 26考研 | 王道 | 计算机组成原理 | 二、数据的表示和运算
  • 上海网站推河北关键词排名推广
  • 游戏代练经济矩阵计算器
  • K8s学习笔记(十一) service
  • 【MCU】【STM32】基于STM32CubeMX+CLion的STM32开发环境
  • 十堰市住房和城乡建设厅官方网站王野天天
  • 【机器人】SG-Nav 分层思维链H-CoT | 在线分层3D场景图 | 目标导航
  • 全面保护隐私的开源个人知识管理工具——SiYuan
  • html5网站开发参考文献无锡网站制作哪家值得信赖
  • python简易程序跑NLPIR模型
  • GPIO 子系统和 pinctrl 子系统
  • 站酷网首页wordpress内容页显示tag
  • linux下的进程间和线程间通信
  • 网站小图片素材商务网站大全
  • Java 集合 “Map(1)”面试清单(含超通俗生活案例与深度理解)
  • 哔哩哔哩国际版分享 | 白色版 ,蓝色概念版
  • 《P2758 编辑距离》
  • unserialize反序列化漏洞
  • 美工网站设计收费网站中的动态统计图如何做
  • LabVIEW谐波失真分析
  • 秦皇岛市网站制作公司民宿可以在哪些网站做推广
  • 【C++】异常介绍:高级应用与性能优化