17. Spring 事务

目录

1. 事务定义

2. MySQL 中的事务使用

3. 没有事务时的插入

4. Spring 编程式事务

5. Spring 声明式事务

5.1  @Transactional 作用范围

5.2  @Transactional 参数说明

5.3  @Transactional 工作原理


1. 事务定义

将⼀组操作封装成一个执行单元(封装到一起),要么全部成功,要么全部失败。
为什么要用事务?
比如转账分为两个操作:
第一步操作:A -100
第二步操作:A+100
果没有事务,第一步执行成功了,第二步执行失败了,那么 A 账户平高白无故的 100 元就没有 了。而如果使用事务就可以解决这个问题,让这⼀组操作要么一起成功,要么一起失败。

2. MySQL 中的事务使用

事务在 MySQL 有 3 个重要的操作:开启事务、提交事务、回滚事务,它们对应的操作命令如下:
--开启事务
start transaction;
--业务执行--提交事务
commit;--回滚事务
rollback;

3. 没有事务时的插入

@Mapper
public interface UserMapper {// 插入数据Integer insert(User user);}
@Data
public class User {private Integer id;private String username;private String password;private String photo;private Date createtime;private Date updatetime;public User(){}public User(String username, String password) {this.username = username;this.password = password;}
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.demo.mapper.UserMapper"><insert id="insert">insert into userinfo (username,password,photo)values(#{username},#{password},#{photo})
</mapper>
@Service
public class UserService {@Autowiredprivate UserMapper userMapper;public Integer insert(User user){return userMapper.insert(user);}
}
@RequestMapping("/trans")
@RestController
public class TransactionalController {@Autowiredprivate UserService userService;@RequestMapping("/addUser")public Integer addUser(String username,String password){User user = new User(username,password);return userService.insert(user);}
}

 在运行前查看数据库的数据如下图所示:

 运行以上代码后可以看到:

此时可以看到数据成功插入: 

4. Spring 编程式事务

@Slf4j
@RequestMapping("/trans")
@RestController
public class TransactionalController {@Autowiredprivate UserService userService;// 获取数据库事务管理器@Autowiredprivate DataSourceTransactionManager dataSourceTransactionManager;private TransactionDefinition transactionDefinition;@RequestMapping("/addUser")public Integer addUser(String username,String password){TransactionStatus transaction = dataSourceTransactionManager.getTransaction(transactionDefinition);User user = new User(username,password);Integer result = userService.insert(user);log.info("影响行数:" +result);// 事务回滚dataSourceTransactionManager.rollback(transaction);return result;}
}

运行成功,返回1: 

 但是,此时可以看到数据库中的数据并未添加:

这是因为事务进行了回滚。接下来我们看一下事务的提交

@Slf4j
@RequestMapping("/trans")
@RestController
public class TransactionalController {@Autowiredprivate UserService userService;// 获取数据库事务管理器@Autowiredprivate DataSourceTransactionManager dataSourceTransactionManager;@Autowiredprivate TransactionDefinition transactionDefinition;@RequestMapping("/addUser")public Integer addUser(String username,String password){TransactionStatus transaction = dataSourceTransactionManager.getTransaction(transactionDefinition);User user = new User(username,password);Integer result = userService.insert(user);log.info("影响行数:" +result);// 事务回滚
//        dataSourceTransactionManager.rollback(transaction);// 提交事务dataSourceTransactionManager.commit(transaction);return result;}
}

可以看到数据此时提交成功:

5. Spring 声明式事务

@Slf4j
@RequestMapping("/trans2")
@RestController
public class TransactionalController2 {@Autowiredprivate UserService userService;@Transactional@RequestMapping("/addUser")public Integer addUser(String username,String password){User user = new User(username,password);Integer result = userService.insert(user);log.info("影响行数:"+result);return result;}
}

 根据打印的日志我们可以看到数据提交成功了:

那么,我们如何让事务进行回滚呢?

手动添加异常:

@Slf4j
@RequestMapping("/trans2")
@RestController
public class TransactionalController2 {@Autowiredprivate UserService userService;@Transactional@RequestMapping("/addUser")public Integer addUser(String username,String password){User user = new User(username,password);Integer result = userService.insert(user);log.info("影响行数:"+result);int a = 10/0;return result;}
}

 运行结果:

 可以看到数据并没有提交:

 查看日志可以发现,此时打印的日志和事务回滚时的日志相同:

此时,我们去掉注解 @Transactional:

@Slf4j
@RequestMapping("/trans2")
@RestController
public class TransactionalController2 {@Autowiredprivate UserService userService;//    @Transactional@RequestMapping("/addUser")public Integer addUser(String username,String password){User user = new User(username,password);Integer result = userService.insert(user);log.info("影响行数:"+result);int a = 10/0;return result;}
}

也就是说,在没有注解 @Transactional 时,数据是可以提交成功的;添加注解 @Transactional,当有异常时,事务会进行回滚。

通过注解,不需要我们手动开启事务和关闭事务,如果程序执行成功,自动提交事务;如果程序执行异常,自动回滚事务。

5.1  @Transactional 作用范围

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

  • 修饰方法:只能应用到 public 方法上,否则不生效
  • 修饰类:表明该注解对该类中所有的 public 方法都生效

5.2  @Transactional 参数说明

接下来,我们设置在发生算数异常时,不进行回滚:

@Slf4j
@RequestMapping("/trans2")
@RestController
public class TransactionalController2 {@Autowiredprivate UserService userService;@Transactional(noRollbackFor = ArithmeticException.class)@RequestMapping("/addUser")public Integer addUser(String username,String password){User user = new User(username,password);Integer result = userService.insert(user);log.info("影响行数:"+result);int a = 10/0;return result;}
}

 接下来我们手动扔出异常:

@Slf4j
@RequestMapping("/trans2")
@RestController
public class TransactionalController2 {@Autowiredprivate UserService userService;/*** 指定异常回滚* @param username* @param password* @return*/@Transactional@RequestMapping("/addUser2")public Integer addUser2(String username,String password) throws Exception {User user = new User(username,password);Integer result = userService.insert(user);log.info("影响行数:"+result);throwException();return result;}public void throwException() throws Exception{throw new IOException();}
}

 可以看到并没有进行回滚。

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

显式的指定所有异常均需回滚:

@Slf4j
@RequestMapping("/trans2")
@RestController
public class TransactionalController2 {@Autowiredprivate UserService userService;/*** 指定异常回滚* @param username* @param password* @return*/@Transactional(rollbackFor = Exception.class)// 显式的指定所有异常均需要回滚@RequestMapping("/addUser2")public Integer addUser2(String username,String password) throws Exception {User user = new User(username,password);Integer result = userService.insert(user);log.info("影响行数:"+result);throwException();return result;}public void throwException() throws Exception{throw new IOException();}
}

可以看到事务进行了回滚:

 如果异常被捕获,事务不会回滚:

@Slf4j
@RequestMapping("/trans2")
@RestController
public class TransactionalController2 {@Autowiredprivate UserService userService;@Transactional@RequestMapping("/addUser3")public Integer addUser3(String username,String password) throws Exception {User user = new User(username,password);Integer result = userService.insert(user);log.info("影响行数:"+result);try{int a = 10/0;}catch (Exception e){e.printStackTrace();}return result;}
}

可以看到事务没有回滚,正常提交: 

5.3  @Transactional 工作原理

@Transactional 是基于 AOP 实现的,AOP 又是使用动态代理实现的。如果目标对象实现了接口,默认情况下会采用 JDK 的动态代理,如果目标对象没有实现了接口,会使用 CGLIB 动态代理。
@Transactional 在开始执行业务之前,通过代理先开启事务,在执行成功之后再提交事务。如果中途到异常,则回滚事务。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/20946.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ffplay——QT项目移植

一、ffmpeg源码编译 参考&#xff1a; https://blog.csdn.net/sgzed/article/details/119850119 在生成时做了一些修改&#xff1a; ./configure --toolchainmsvc --enable-shared --enable-postproc --enable-gpl --prefixwindows 二、对文件做调整 ffplay只需要三个文件&…

stm32常见数据类型

stm32的数据类型的字节长度 s8 占用1个byte&#xff0c;数据范围 -2^7 到 (2^7-1) s16 占用2个byte&#xff0c;数据范围 -2^15 到 (2^15-1) s32 占用 4个byte&#xff0c;数据范围 -2^31 到 (231-1)231 2147483647 int64_t占用8个byte&#xff0c;数据范围 -2^63 到 (2^63-1)…

一文快速入门Byzer-python

目录 一、Byzer-Python介绍 二、Byzer-python工具语法糖 三、环境依赖 1. Python 环境搭建 2. Ray 环境搭建 3. Byzer-python 与 Ray 四、参数详解 五、数据处理 1. Byzer-python 处理数据 2. Byzer-python 代码说明 3. Byzer-python 读写 Excel 文件 4. Byzer-pytho…

如何搭建一个口才培训的网站?需要具备哪些条件?

论文题目&#xff1a;如何搭建一个口才培训的网站及所需条件 摘要&#xff1a; 本文探讨了如何搭建一个口才培训的网站&#xff0c;并详细分析了所需的关键条件。口才培训作为一种重要的社交技能&#xff0c;能够帮助人们提升自信和影响力&#xff0c;因此具有广阔的市场前景。…

day17 | 654.最大的二叉树 617.合并二叉树 700.二叉搜索树中的搜索 98.验证二叉搜索树

文章目录 一、最大的二叉树二、合并二叉树三、二叉搜索树中的搜索四、验证二叉搜索树 一、最大的二叉树 654.最大的二叉树 构建二叉树的题目&#xff0c;都用前序遍历。 因为我们一定要先构建根节点&#xff0c;才能继续向后构建。 递归函数的参数和返回值&#xff1a; Tree…

AssetBundle学习

官方文档&#xff1a;AssetBundle 工作流程 - Unity 手册 (unity3d.com) 之前写的博客&#xff1a;AssetBundle学习_zaizai1007的博客-CSDN博客 使用流程图&#xff1a; 1&#xff0c;指定资源的AssetBundle属性 &#xff08;xxxa/xxx&#xff09;这里xxxa会生成目录&…

redux-promise-middleware和applyMiddleware的理解与使用

一、作用&#xff1a; applyMiddleware是一个中间件&#xff0c;通常和applyMiddleware结合使用&#xff0c;是dispatch与reducers之间的应用&#xff0c;用于处理dispatch发送的异步action操作 二、使用 1、安装redux-promise-middleware cnpm i redux-promise-middleware…

Micropython STM32F4入门点灯第一课

Micropython STM32F4入门点灯第一课 &#x1f4cc;固件刷可参考前面一篇《STM32刷Micropython固件参考指南》&#x1f4cd;固件下载&#xff1a;https://micropython.org/download/?mcustm32f4&#x1f516;本例程基于STM32F4DISC&#xff0c;主控芯片STM32F407VGT6&#x1f4…

vue 混入(mixin)的使用

在 vue 组件内&#xff0c;如果想将一些公共功能&#xff0c;如组件、方法、钩子函数等复用&#xff0c;混入是一个很好的选择。 现在开始我们的混入使用吧 1、我们可以创建一个目录mixins&#xff0c;在创建一个comment.js文件如图&#xff1a; // 在 common.js 里写你想共享…

20230803激活手机realme GT Neo3

20230803激活手机realme GT Neo3 缘起&#xff1a; 新买的手机&#xff1a;realme GT Neo3 需要确认&#xff1a; 1、4K录像&#xff0c;时间不限制。 【以前的很多手机都是限制8/10/12/16分钟】 2、通话自动录音 3、定时开关机。 4、GPS记录轨迹不要拉直线&#xff1a;户外助…

小程序学习(四):WXML模板语法

WXML模板语法-数据绑定 1.数据绑定的基本原则 ①在data中定义数据 ②在WXML中使用数据 2.动态绑定属性 WXML模板语法-事件绑定 3.什么是事件 4.小程序中常用的事件 5.事件对象的属性列表 6.target和currentTarget的区别 7.bindtap的语法格式 8.在事件处理函数中为data中的数据…

DC-2靶机

文章目录 信息收集漏洞发现漏洞利用 DC-2介绍 DC-2环境下载 请注意&#xff0c;您需要将渗透测试设备上的 hosts 文件设置为&#xff1a; 192.168.0.145 dc-2 显然&#xff0c;将 192.168.0.145 替换为 DC-2 的实际 IP 地址。 它将使生活变得更加简单&#xff08;如果没有它&am…

LeetCode513. 找树左下角的值

513. 找树左下角的值 文章目录 [513. 找树左下角的值](https://leetcode.cn/problems/find-bottom-left-tree-value/)一、题目二、题解方法一&#xff1a;递归法&#xff08;层序遍历&#xff0c;深度优先搜索&#xff09;**不足之处以及如何改进** 方法二&#xff1a;迭代 一、…

Gitignore忽略文件

默认情况下&#xff0c;Git会监视我们项目中的所有内容&#xff0c;但是有些内容比如mode_modules中的内容&#xff0c;我们不希望他被Git所管理。 我们可以在我们项目目录中添加一个 .gitignore 文件来设置那些需要git忽略的文件。

屏幕取色器Mac版_苹果屏幕取色工具_屏幕取色器工具

Sip for Mac 是Mac系统平台上的一款老牌的颜色拾取工具&#xff0c;是设计师和前端开发工作者必不可少的屏幕取色软件&#xff0c;你只需要用鼠标点一下即可轻松地对屏幕上的任何颜色进行采样和编码&#xff0c;并将颜色数据自动存到剪切板&#xff0c;方便随时粘贴出来。 Sip…

GPIO简介

一、GPIO GPIO&#xff08;General-purpose input/output&#xff09;即通用型输入输出&#xff0c;GPIO可以控制连接在其之上的引脚实现信号的输入和输出 芯片的引脚与外部设备相连&#xff0c;从而实现与外部硬件设备的通讯、控制及信号采集等功能 LED实验步骤 实验步骤 以L…

Spring事务传播机制、实现方式、失效场景即原理

贴一篇源码分析的好文章&#xff1a;https://blog.csdn.net/qq_30905661/article/details/114400417 本质&#xff1a; 一个事务对应一个数据库连接。 通过 this 来调用某个带有 Transactional 注解的方法时&#xff0c;这个注解是失效的&#xff0c;可以看做这个方法&#x…

Cocos Creator不规则按钮

实现该功能需要用到组件PolygonCollider2D&#xff0c;官方链接&#xff1a; https://docs.cocos.com/creator/3.4/manual/zh/physics-2d/physics-2d-collider.html 创建组件 创建一个精灵节点&#xff1a; 创建碰撞组件PolygonColider2D&#xff0c;如图 给按钮添加多边形碰…

链表的总体涵盖以及无哨兵位单链表实现——【数据结构】

&#x1f60a;W…Y&#xff1a;个人主页 在学习之前看一下美丽的夕阳&#xff0c;也是很不错的。 如果觉得博主的美景不错&#xff0c;博客也不错的话&#xff0c;关注一下博主吧&#x1f495; 在上一期中&#xff0c;我们说完了顺序表&#xff0c;并且提出顺序表中的问题 1. 中…

无涯教程-Lua - 函数声明

函数是一起执行任务的一组语句&#xff0c;您可以将代码分成单独的函数。 Lua语言提供了程序可以调用的许多内置方法。如方法 print()打印在控制台中作为输入传递的参数。 定义函数 Lua编程语言中方法定义的一般形式如下- optional_function_scope function function_name(…