【spring】spring 的事务(transaction) 三 try catch对事务的影响

2023-11-09


相关文章
spring 的事务(transaction) 一 基础概念介绍
spring 的事务(transaction) 二 陷阱
spring 的事务(transaction) 三 try catch对事务的影响
spring 的事务(transaction) 四 嵌套事务PROPAGATION_NESTED

概述

外层事务和内层事务基础概念知晓后,需要结合try catch才能真正理解,因为try catch会影响异常的传递。

本篇文章强调了外层和内存,以Propagation.REQUIRED+Propagation.REQUIRED为例,看过前面《spring 的事务(transaction) 一 基础概念介绍》一文的话,知道这二者是独立事务,而不是父子事务。针对父子事务,会单独写篇文章来介绍。

try catch可以加在内层,也可以在外层。 虽然外层和内存

1. 非异常用例

我们开始一个经典的嵌套用例。

1.1 创建工程

我们先创建一个spring的工程,利用spring 单元测试架构,来写用例

工程的创建参见 用SpringBoot创建mysql工程,后续以该工程为基础改造用例。

数据库脚本,新增一个:

CREATE TABLE `order` (
  `id` INT(11) NOT NULL,
  `price` VARCHAR(10) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8

INSERT INTO `order` (`id`, `price`) VALUES(1,'100');
INSERT INTO `order` (`id`, `price`) VALUES(2,'150');

项目整体视图:

在这里插入图片描述
MysqldemoApplication:

package com.example.mysqldemo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.transaction.annotation.EnableTransactionManagement;

@SpringBootApplication
@ComponentScan("com.example")   //设置扫描路径
@EnableTransactionManagement   //开启事务
public class MysqldemoApplication {

	public static void main(String[] args) {
		SpringApplication.run(MysqldemoApplication.class, args);
	}

}


定义2个接口,分别是IOrderService和IUserService:

package com.example.service;

public interface IOrderService {

    public void  addOrder(int id, String name);

}

package com.example.service;

public interface IUserService {

    public void  addUser(int id, String name);

}

定义2个实现类:

package com.example.service;


import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

@Service
public class OrderServiceImpl implements IOrderService {


    @Autowired
    private JdbcTemplate jdbcTemplate;


    @Transactional(propagation = Propagation.REQUIRES_NEW)
    @Override
    public void addOrder(int id, String price) {
        //order是mysql关键词,必须用`号(tab键上方的那个键,波浪线键)包裹起来
        jdbcTemplate.execute("insert into `order` values ("+id+",'"+price+"')");

    }
}


package com.example.service;


import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

@Service
public class UserServiceImpl implements IUserService {


    @Autowired
    private JdbcTemplate jdbcTemplate;

    @Autowired
    private IOrderService orderService;

    @Transactional(propagation = Propagation.REQUIRES_NEW)
    @Override
    public void addUser(int id, String name) {
        jdbcTemplate.execute("insert into `student` values (" + id + ",'" + name + "')");
        try {
           //注意:此时有try catch
            orderService.addOrder(3, "110");
        } catch (Exception e) {
            System.out.println(e);
        }
    }

}


application.properties:

#集成mysql数据库的配置
spring.datasource.driverClassName=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://10.40.65.183:3306/test
spring.datasource.username=
spring.datasource.password=

测试用例:

package com.example.mysqldemo;

import com.example.service.IUserService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)
@SpringBootTest(classes = MysqldemoApplication.class)
public class MysqldemoApplicationTests {

	@Autowired
	private IUserService userService ;


	@Test
	public void insert() {
		userService.addUser(4,"hanmeimei");
	}

}

此时我们在此时用例中插入一个用户数据,而在内部,会插入一个订单信息。

如果数据库存在脏数据,可以先清除脏数据。

1.2 执行

执行后,数据都是正常插入的,原因是没有任何异常出现:
在这里插入图片描述
注意:此时addUser()内有try catch,这是标准用法:

    public void addUser(int id, String name) {
        jdbcTemplate.execute("insert into `student` values (" + id + ",'" + name + "')");
        try {

            orderService.addOrder(3, "110");
        } catch (Exception e) {
            System.out.println(e);
        }
    }

2. 内层抛出非check异常,外层进行捕获

结论:符合预期,内层回滚,外层不回滚。内层抛出非check异常,自动帮我们回滚内层事务,外层捕获内层异常,避免异常传递至外层,外层不回滚。

注意:我们定义的外层和内存事务都是REQUIRES_NEW,如果是其他事务,又是另一个结论。

我们模拟在orderservice.addOrder()内抛出一个ArithmeticException异常,这是个非check异常。

按照预期,内层事务出现非check异常,会自动回滚,而外层没有出现错误,不会回滚。

   System.out.println( 1/0);

在这里插入图片描述
重新执行:
在这里插入图片描述
总结:

  • 内层事务抛出非check异常,并且内部没有try catch,这样内层声明的事务能捕获该异常,自动帮我们回滚内层事务
  • 外层自身没有抛出异常,并且通过try catch ,捕获了内层异常,使得内部异常没有传递到外层,外层等价于没有异常,不会回滚

在这里插入图片描述

3. 内层抛出非check异常,外层不进行捕获

在2章节里面,我们就强调过 外层没有加try catch时,内存抛出异常后,会导致异常传递至外层,引发外层也回滚

下面我们来验证下上述结论:

注释掉外层方法的try catch:

    public void addUser(int id, String name) {
        jdbcTemplate.execute("insert into `student` values (" + id + ",'" + name + "')");


        orderService.addOrder(3, "110");

我们来验证下,确实都没有出现新增的数据:
在这里插入图片描述
过程分析:
在这里插入图片描述

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【spring】spring 的事务(transaction) 三 try catch对事务的影响 的相关文章

随机推荐

  • HTML <colgroup> 标签

    实例 两个 colgroup 元素为表格中的三列规定了不同的对齐方式和样式 注意第一个 colgroup 元素横跨两列 table width 100 border 1 table
  • [138]小米笔记本怎么关闭secure boot

    关闭Secure Boot的步骤 一 关闭 快速启动 功能 1 右键 开始菜单 电源选项 进入后 点击 选择电源按钮的功能 2 进入电源选项设置后 点击 更改当前不可用的设置 再把 启用快速启动 推荐 前边的勾去掉 若没有该选择则不需要操作
  • MDK与芯片的联系

    程序执行的时候FLASH空间 code RO data 程序执行时SRAM空间 RW data ZI data 程序存储时占用空间 code RO data RW data 在目录下打开命令行窗口 按shift 鼠标右键 gt 可以将信息输
  • 区块链:Solidity值类型(Solidity 枚举Enums & 结构体Structs)

    枚举Enums 案例 pragma solidity 0 4 4 contract test enum ActionChoices GoLeft GoRight GoStraight SitStill ActionChoices choic
  • 华为OD机试 C++ 叠积木

    题目 你手里有一堆砖头 它们都有一样的宽和高 但长度不同 你想用这些砖头堆砌一堵墙 每一层墙可以只用一个砖头 也可以用两个拼接起来 但这两种情况下 每层的长度必须都是一样的 如果你想使用所有的砖头 并堆砌出尽可能多的层数 那么最多可以搭建多
  • C#(winform)调用pytorch模型

    winform调用pytorch上训练好的unet模型 项目是写一个辅助诊断系统软件 用winform写软件 调用pytorch和matlab的模型 这篇博客只包含调用pytorch模型的部分 1 c libtorch 调用模型 2 c 生
  • java使用aspose.pdf或者spire.pdf 将pdf文件转word,实测

    1 aspose pdf aspose pdf不是破解版的只能转3页 所以我弄了个破解版 aspose pdf破解版在网上都有破解方法也比较简单 这里就不说了 直接引入破解版的jar包 在这里我用的是aspose pdf 21 11 jar
  • Qt第四十五章:QComboBox 禁止滚轮

    很简单 直接反射将QComboBox的wheelEvent方法重置掉即可 self combo box QComboBox self setattr self combo box wheelEvent lambda a None
  • 车联网Apollo(阿波罗),研究carlife车机端集成及开发,(WeLink,carplay/carlife)

    Apollo 阿波罗 是携程框架部门研发的分布式配置中心 能够集中化管理应用不同环境 不同集群的配置 配置修改后能够实时推送到应用端 并且具备规范的权限 流程治理等特性 适用于微服务配置管理场景 https github com ctrip
  • C语言提取一列数据并保存

    c语言求教 txt文档只有一列数据但是有很多 需要把它提取出来 每1024个数保存在一个文件中 求大神指教 c语言
  • 什么时候需要使用引用?使用引用的好处是什么?

    作者 谢之易 链接 https www zhihu com question 34267829 answer 58414818 来源 知乎 著作权归作者所有 商业转载请联系作者获得授权 非商业转载请注明出处 记忆里 C 的设计与演化 一书提
  • 【华为机试真题 Python实现】仿 LISP 运算【2022 Q1 Q2

    题目描述 LISP 语言唯一的语法就是括号要配对 形如 OP P1 P2 括号内元素由单个空格分割 其中第一个元素 OP 为操作符 后续元素均为其参数 参数个数取决于操作符类型 注意 参数 P1 P2 也有可能是另外一个嵌套的 OP P1
  • 语音识别-初识

    ASRT https blog ailemon net 2018 08 29 asrt a chinese speech recognition system ASR Automatic Speech Recognition Paddle
  • 计算机加入域的一种方法

    重装系统后 想把机子加入域 却总是不成功 隐约记得以前老大们讲过 厚着脸皮问了 o 之后 决定记下来 省的我以后又忘了 计算机加入域 一 在网络中加入DNS地址 二 step 1 更改计算机名字 右键点击 我的电脑 打开 属性 页面 找到
  • redis-benchmark测试Redis集群性能

    基础环境配置 Redis5 三主三从cluster 1 100个并发连接 100000个请求 检测host为172 16 254 124端口为7004的redis服务器性能 redis benchmark h 172 16 254 124
  • C# 单例模式详解

    定义 单例模式是比较常见的一种设计模式 目的是保证一个类只能有一个实例 而且自行实例化并向整个系统提供这个实例 避免频繁创建对象 节约内存 单例模式的应用场景很多 比如我们电脑的操作系统的回收站就是一个很好的单例模式应用 电脑上的文件 视频
  • 2023年大唐杯仿真部分-5G信令流程仿真实验

    参考视频连接 第十届大唐杯信令流程仿真讲解 哔哩哔哩 bilibili 1 5G系统消息的获取 根据题目要求 UE开机需要获取消息 消息分别是MIB SIB1 SIB2 SIB3 上面为什么选的是SIB1 Systeminformation
  • 如何判断一个指定的经纬度点是否落在一个多边形内

    1 理论支持 如果从需要判断的点出发的一条射线与该多边形的焦点个数为奇数 则该点在此多边形内 否则该点在此多边形外 射线不能与多边形顶点相交 2 编程思路 该程序的思路是从A点出发向左做一条水平射线 平行于x轴 向X轴的反方向 判断与各边是
  • Golang实现一个事务型内存数据库

    内存数据库经我们经常用到 例如Redis 那么如何从零实现一个内存数据库呢 本文旨在介绍如何使用Golang编写一个KV内存数据库MossDB 特性 MossDB是一个纯Golang编写 可嵌入的 键值型内存数据库 包含以下特性 可持久化
  • 【spring】spring 的事务(transaction) 三 try catch对事务的影响

    文章目录 概述 1 非异常用例 1 1 创建工程 1 2 执行 2 内层抛出非check异常 外层进行捕获 3 内层抛出非check异常 外层不进行捕获 相关文章 spring 的事务 transaction 一 基础概念介绍 spring