Springboot基础系列:事务回滚

2023-05-16

1 场景

一个服务中有存在多个数据库事务,要求:

  • 保证数据一致
  • 不产生脏数据
  • 不误删数据
    即前面的事务正常运行,后面的事务出现异常,数据库保持调用该服务前的状态

2 方案

Springboot开启事务,在Service实现层添加@Transactional注解,但是该注解默认捕捉RuntimeException和Error异常,出现如Exception异常时,需要手动捕捉,即不手动捕捉,会出现@Transactional注解失效.

2.1 原生回滚

使用默认的@Transactional回滚策略,即@Service实现层多个事务不使用try…catch,若出现事务异常,服务层会自动回滚.

2.1.0 Code

两个保存事务,第一个保存事务正常执行,两个事务之间添加一个异常,此时回滚生效,数据库不会新增任何数据.

package com.company.web.service.impl;

import com.company.web.service.IDataSaveService;
import com.company.web.mapper.QuestionsMapper;
import com.company.web.mapper.AnswersMapper;
import com.company.web.dto.*;

import java.util.Map;

import javax.annotation.OverridingMethodsMustInvokeSuper;

import java.util.HashMap;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;

/**
 * Data save implements. 
 * @author xindaqi 
 * @since 2020-10-20
 */
@Service 
@Transactional
public class DataSaveServiceImpl implements IDataSaveService{

    @Autowired 
    private QuestionsMapper questionsMapper;

    @Autowired
    private AnswersMapper answersMapper;

    @Override 
    public Boolean saveQuestionAndAnswerWithTransactionRollback(QuestionAnswerInputDTO params) {

        Map<String, String> questionsMap = new HashMap<>();
        questionsMap.put("questions", params.getQuestions());
        Integer addQuestionFlag = questionsMapper.addQuestions(questionsMap);

        Integer errorFlag = 1/0;
        Map<String, String> answersMap = new HashMap<>();
        answersMap.put("answers", params.getAnswers());
        answersMap.put("questions", params.getQuestions());
        Integer addAnswerFlag = answersMapper.addAnswers(answersMap);
        return true;

        
    } 
    
}

2.1.2 结果

第一个事务正常存储,两个事务之间出现异常时,事务回滚,通过日志Transaction synchronization deregistering可知,此时执行了回滚,注销了SqlSession.

Creating a new SqlSession
Registering transaction synchronization for SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@336086cf]
JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@73698f0d] will be managed by Spring
==>  Preparing: insert into questions_repository (questions) values (?) 
==> Parameters: Q2020-10-20-2(String)
<==    Updates: 1
Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@336086cf]
Transaction synchronization deregistering SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@336086cf]
Transaction synchronization closing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@336086cf]
java.lang.ArithmeticException: / by zero
        at com.company.web.service.impl.DataSaveServiceImpl.saveQuestionAndAnswer(DataSaveServiceImpl.java:37)
        at com.company.web.service.impl.DataSaveServiceImpl$$FastClassBySpringCGLIB$$b95c5951.invoke(<generated>)

2.2 try吃掉回滚

由于Springboot2的@Transactional默认只能捕捉RuntimeException异常,当出现如Exception的异常时,该异常则不能捕捉,数据库出现数据不一致.

2.2.1 Code

在@Service实现层,多个事务使用try…catch,产生的Exception异常,会被代码捕捉,事务@Transactional无法捕捉,当多个事务之间出现异常时,数据库会执行运行正常的事务,不会回滚,此时会产生脏数据或数据不一致(误删).

package com.company.web.service.impl;

import com.company.web.service.IDataSaveService;
import com.company.web.mapper.QuestionsMapper;
import com.company.web.mapper.AnswersMapper;
import com.company.web.dto.*;

import java.util.Map;

import javax.annotation.OverridingMethodsMustInvokeSuper;

import java.util.HashMap;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;

/**
 * Data save implements. 
 * @author xindaqi 
 * @since 2020-10-20
 */
@Service 
@Transactional
public class DataSaveServiceImpl implements IDataSaveService{

    @Autowired 
    private QuestionsMapper questionsMapper;

    @Autowired
    private AnswersMapper answersMapper;

    @Override 
    public Boolean saveQuestionAndAnswerWithTryCatchWithoutRollback(QuestionAnswerInputDTO params) {
        try {
            Map<String, String> questionsMap = new HashMap<>();
            questionsMap.put("questions", params.getQuestions());
            Integer addQuestionFlag = questionsMapper.addQuestions(questionsMap);

            Integer errorFlag = 1/0;
            Map<String, String> answersMap = new HashMap<>();
            answersMap.put("answers", params.getAnswers());
            answersMap.put("questions", params.getQuestions());
            Integer addAnswerFlag = answersMapper.addAnswers(answersMap);
            return true;

        }catch(Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    
    
}

2.2.2 结果

Sprinboot原生的事务@Transactional无法捕捉Exception异常,成功的事务会正常操作数据库,数据库的数据部分发生改变.

Creating a new SqlSession
Registering transaction synchronization for SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@621d38e5]
JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@45d439b9] will be managed by Spring
==>  Preparing: insert into questions_repository (questions) values (?) 
==> Parameters: Q2020-10-20-2(String)
<==    Updates: 1
Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@621d38e5]
java.lang.ArithmeticException: / by zero
        at com.company.web.service.impl.DataSaveServiceImpl.saveQuestionAndAnswerWithTryCatchWithoutRollback(DataSaveServiceImpl.java:54)
        at com.company.web.service.impl.DataSaveServiceImpl$$FastClassBySpringCGLIB$$b95c5951.invoke(<generated>)

2.3 rollbackfor捕捉回滚

当多个事务出现@Transactional无法捕获的异常,如Exception时,需要手动捕获异常,在注解中添加rollbackfor捕捉指定的异常类.

@Transactional(rollbackFor = Exception.class)

当然这还不够,需要在catch中添加回滚处理方法,才能最终实现回滚.

try{
    //TODO: mutiple transaction.
}catch(Exception e){
    TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
}

2.3.1 Code

在方法上添加事务注解并指定回滚的异常类型,在catch中添加回滚方法setRollbackOnly(),当出现Exception异常时,捕获当前的异常并回滚.

package com.company.web.service.impl;

import com.company.web.service.IDataSaveService;
import com.company.web.mapper.QuestionsMapper;
import com.company.web.mapper.AnswersMapper;
import com.company.web.dto.*;

import java.util.Map;

import javax.annotation.OverridingMethodsMustInvokeSuper;

import java.util.HashMap;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;

/**
 * Data save implements. 
 * @author xindaqi 
 * @since 2020-10-20
 */
@Service 
@Transactional
public class DataSaveServiceImpl implements IDataSaveService{

    @Autowired 
    private QuestionsMapper questionsMapper;

    @Autowired
    private AnswersMapper answersMapper;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean saveQuestionAndAnswerWithTryCatchWithRollback(QuestionAnswerInputDTO params) {
        try {
            Map<String, String> questionsMap = new HashMap<>();
            questionsMap.put("questions", params.getQuestions());
            Integer addQuestionFlag = questionsMapper.addQuestions(questionsMap);

            Integer errorFlag = 1/0;
            Map<String, String> answersMap = new HashMap<>();
            answersMap.put("answers", params.getAnswers());
            answersMap.put("questions", params.getQuestions());
            Integer addAnswerFlag = answersMapper.addAnswers(answersMap);
            return true;

        }catch(Exception e) {
            e.printStackTrace();
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            return false;
        }
    }
    
}

2.3.2 结果

事务之间出现异常时,先抛出异常,在异常之后,会执行回滚,即Transaction synchronization deregistering SqlSession注销SqlSession.

Creating a new SqlSession
Registering transaction synchronization for SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@252bc44f]
JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@41f5088d] will be managed by Spring
==>  Preparing: insert into questions_repository (questions) values (?) 
==> Parameters: Q2020-10-20-7(String)
<==    Updates: 1
Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@252bc44f]
java.lang.ArithmeticException: / by zero
        at com.company.web.service.impl.DataSaveServiceImpl.saveQuestionAndAnswerWithTryCatchWithRollback(DataSaveServiceImpl.java:79)
        at com.company.web.service.impl.DataSaveServiceImpl$$FastClassBySpringCGLIB$$b95c5951.invoke(<generated>)
        at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218)
       ........
Transaction synchronization deregistering SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@252bc44f]
Transaction synchronization closing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@252bc44f]

3 小结

  • Springboot2事务回滚方式:
序号方式备注
1自动@Service实现层添加@Transactional注解
2手动方法上添加@Transactional注解使用过rollbackFor参数捕获指定异常类
在catch中使用setRollbackOnly()方法回滚
  • 事务回滚标志:
    Transaction synchronization deregistering SqlSession

[参考文献]
[1]https://blog.csdn.net/weixin_44874115/article/details/104392779
[2]https://www.cnblogs.com/myitnews/p/12364455.html
[3]https://www.cnblogs.com/jpfss/p/11152338.html

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

Springboot基础系列:事务回滚 的相关文章

  • 网络测试技术——802.1X_MD5认证(下篇)

    上篇我们讲到802 1X MD5的简介 认证过程 测试组网以及测试环境准备 xff0c 本期我们将为大家带来测试的详细步骤 xff1a 六 测试仪配置 1 占用端口 端口功能 xff08 1 xff09 端口1用来模拟DOT1X和发送流量
  • 网络测试技术——802.1X TLS认证(上篇)

    一 TLS认证简介 1 TLS认证 xff08 1 xff09 认证过程 最安全认证技术 实施最复杂 xff08 2 xff09 TLS双向证书认证 服务器对客户端进行认证 客户端对服务器进行认证 2 TLS认证过程 3 交换机认证模式 x
  • SRv6测试技术简介

    什么是SRv6 xff1f SRv6技术就是采用现有的IPv6转发技术 xff0c 通过扩展IPv6报文的头域 xff0c 实现类似标签转发的处理 SRv6将一些IPv6地址定义成实例化的SID xff08 Segment ID xff09
  • RENIX 软件RAW流发送——网络测试仪实操

    本文主要介绍了RENIX软件如何进行RAW流发送操作 文章通过预约端口 添加RAW流 修改负载 发送流量 查看流统计 数据包捕获六个步骤详细介绍了操作过程 步骤一 xff1a 预约端口 1 先安装RENIX软件 xff0c 正确安装情况下桌
  • RENIX软件OSPF和BFD、ISIS和BFD联动测试——网络测试仪实操

    本文介绍了RENIX软件BFD测试相关操作 xff0c 全文分为五大部分 第一部分为BFD概述 xff1b 第二部分为搭建OSPF和BFD联动测试环境 xff1b 第三部分为OSPF和BFD联动测试配置 xff1b 第四部分为搭建ISIS和
  • 信而泰 X-Snapper测试系统,助力家庭路由器IPv6支持度测试

    随着互联网的蓬勃发展 xff0c 宝贵而有限的IPv4地址资源一直在被分配使用 2019年11月25日 xff0c 负责英国 欧洲 中东和部分中亚地区互联网资源分配的欧洲网络协调中心 xff08 RIPE NCC xff09 宣布 xff0
  • 如何使用测试仪进行400G交换机性能测试

    一 400G以太网概述 400G以太网或400 Gigabit Ethernet 400GbE 由 IEEE P802 3bs Task Force 于 2017 年开发 xff0c 它使用与100 Gigabit Ethernet 大致相
  • 【python3】简易双因子Radius认证服务器,带UI界面

    需要将dictionary rfc2865放在运行的同级目录下 coding utf 8 from tkinter import from tkinter ttk import from tkinter import scrolledtex
  • 信而泰测试方案,助力客户打造网络安全防护“金钟罩”

    一 网络安全行业面临的挑战 据 Cybercrime Magazine 在最近一份报告中称 xff0c 仅2021年 xff0c 黑客攻击和各种网络犯罪就给全球经济造成了超过6万亿美元的损失 xff0c 预计到2025年 xff0c 此类犯
  • BGP BFD测试案例

    一 BFD原理 1 1 BFD技术简介 一种全网统一 检测迅速 监控网络中链路或者IP路由的双向转发连通状况 xff0c 并未上层应用提供服务的技术 1 2 BFD会话建立方式和监测机制 BFD的标识符 xff1a xff08 1 xff0
  • 数据中心典型测试场景浅析

    数据中心概述 数据中心泛指拥有众多服务器的大型机房 xff0c 通过利用通信运营商已有的互联网通信线路 带宽资源 xff0c 建立标准化的数据中心机房环境 xff0c 具有运行速度快 存储量大 安全性高等特点 数据中心东西向流量的占比更大
  • Vxlan协议原理及基本配置——网络测试仪实操手册

    一 Vxlan协议原理 1 Vxlan协议相关术语 一 缩略语 OSI中的概念 NVE Network Virtualization Edge 网络虚拟边缘节点 VTEP VXLAN Tunnel Endpoints xff0c VXLAN
  • 如何模拟VTEP下大量VM主机ARP消息——网络测试仪实操

    模拟VTEP下大量VM主机ARP消息 xff0c 按照下面的步骤 xff1a 1 打开 Renix 软件 xff0c 连接机框并预约测试端口 xff1b 2 创建一条RAW流量 xff08 Binding流量也可以 xff0c 这里用RAW
  • 信而泰自动化OSPFv2测试小技巧

    OSPFv2协议简介 OSPFv2 xff08 开放式最短路径优先版本2 xff09 是互联网协议 xff08 IP xff09 网络的路由协议 它使用链路状态路由 xff08 LSR xff09 算法 xff0c 并且属于在单个自治系统
  • OpenFlow协议原理及基本配置-网络测试仪实操

    一 OpenFlow协议原理 1 OpenFlow技术背景 转发和控制分离是SDN网络的本质特点之一 在SDN网络架构中 xff0c 控制平面与转发平面分离 xff0c 网络的管理和状态在逻辑上集中到一起 xff0c 底层的网络基础从应用中
  • 如何使用向导创建Openflow 流表-网络测试仪实操

    使用向导创建Openflow中的FlowTable xff0c 按照下面的步骤 xff1a 1 打开Renix软件 xff0c 连接机框并预约测试端口 xff1b 2 配置一个IPv4接口 3 配置一个OpenFlowController绑
  • 信而泰OLT使用介绍-网络测试仪实操

    一 OLT产品介绍 1 概述 PON作为FTTX网络发展的核心技术 xff0c 局端设备OLT尤其重要 本文档中主要介绍OLT的功能特性 业务配置 2 基本功能特性 2 1大容量和高集成度 ZXA10 C300集光接入 数据交换 路由处理于
  • 信而泰耦合测试-网络测试仪实操

    一 耦合测试原理 1 产生背景 常用测试无线设备过程中 xff0c 将无线设备置于屏蔽箱中 xff0c 通过无线网卡连接并运行iperf等类似软件的方式检测所述无线设备的吞吐量 相关技术中将所述无线设备置于所述屏蔽箱中的检测方法 xff0c
  • 【python】程序绑定PC和时间戳做定期授权码

    取磁盘编码或者网卡编码 43 时间戳16位格式 关于时间戳 xff0c 当前简单的实现是年月日转成对应的16位 xff0c 比如 23 03 28 gt 173E xff08 日先直接整除2 xff0c 每月不会超过31天 xff0c 整除
  • 信而泰ALPS 用户管理——网络测试仪实操

    本文介绍了如何在ALPS平台上Step By Step进行用户管理 用户管理介绍 设备在出厂时 xff0c 提供了一个默认管理员账号 xff0c 该账号为admin admin 管理员账号除了可用于测试之外 xff0c 还具有用户管理权限

随机推荐

  • 信而泰RENIX 802.1ag功能介绍-网络测试仪实操

    一 EOAM概述 1 以太网 1 1以太网优点 简单易用 价格低廉 高拓展性 大势所趋 xff0c 一统天下 1 2以太网缺点 可管理性差 定位故障手段少 定位故障速度慢 维护成本高 2 以太网OAM EOAM 为运营商服务 提高以太网可靠
  • 信而泰BGP Flow Spec防攻击测试解决方案

    随着互联网行业的迅猛发展 xff0c 越来越多的业务都从线下走到了线上 互联网在给大家生活带来便利的同时也面临着防护自身安全的各种挑战 DoS DDoS攻击是对网络安全的重大威胁 xff0c 攻击者通过多个控制端控制成千上万的攻击设备对同一
  • 信而泰X1多速率板卡写入SN号和ID——网络测试仪实操

    一 X1多速率板卡SN号和ID说明 速率的License文件需要根据板卡SN号和ID来制作 3 1 6正式版本 xff0c DarYu L2 7高性能 网络测试仪 支持用户通过Renix查看板卡SN号号 但是有的板卡可能存在没有SN号和ID
  • renix如何查看时延和抖动和丢包——网络测试仪实操

    目录 查看时延和抖动 一 预约测试资源 二 新建流 三 查看时延和抖动 查看丢包 一 预约端口 二 创建Raw流 三 如何查看流量的实时丢包个数和丢包比例 查看时延和抖动 一 预约测试资源 打开Renix软件 xff0c 连接机箱 预约端口
  • IP 网络主动监测系统 Renix Active

    一 IT网络运维面临的挑战 1 网络性能可视化 与公有云和SaaS平台连接的可靠性 广域网线路性能 互联网专线性能 2 诊断工具 现场无IT工程师覆盖 诊断的人力费用 网络与应用系统的纠结 3 用户体验 Web应用的访问质量 语音语音视频的
  • FEC原理与操作及BigTao机框装机说明

    一 FEC原理与操作 1 FEC 原理简介 前向纠错 xff08 英语 xff1a forward error correction xff0c 缩写FEC xff09 或信道编码 xff08 英语 xff1a channel coding
  • 信而泰RENIX时延抖动原理和计算公式、流量“重复次数”的使用、通道的作用

    一 信而泰Renix时延抖动原理和计算公式 信而泰RENIX时延抖动原理和计算公式 流量 重复次数 的使用 通道的作用 1 时延抖动原理 时延抖动是网络监视和测量的一个重要指标 在VoIP或视频流中 xff0c 数据包以连续流的形式发送 x
  • 从单体式架构迁移到微服务架构

    迁移到微服务综述 迁移单体式应用到微服务架构意味着一系列现代化过程 xff0c 有点像这几代开发者一直在做的事情 xff0c 实时上 xff0c 当迁移时 xff0c 我们可以重用一些想法 一个策略是 xff1a 不要大规模 xff08 b
  • boost库编译参数小结

    编译boost库 32位编译 xff1a 从开始菜单启动Visual Studio 2013的vs2013 命令行 xff0c 进入boost所在目录 xff0c 运行bootstrap bat 编译命令 xff08 例 xff09 xff
  • 【python】动态运行py文件并生成exe可执行程序

    main py if name 61 61 39 main 39 if len sys argv gt 1 file path 61 sys argv 1 check folder 61 os path dirname file path
  • 麒麟V10 root登录系统

    麒麟V10 root登录系统 提示 xff1a 麒麟V10桌面操作系统 xff0c 安全性考虑不允许root登录的 一 root登录界的图片 root登录界面如图所示 xff0c 需要手动输入用户名和密码 二 使用步骤 1 设置root密码
  • ALTIUM_ROOM格式复制

    特别注意通道号要对应相同 1 D M T 从选择的器件产生矩形的ROOM 2 如图 xff1a 3 4 D M C 先后点击参照布局和未布局 5 设置如下 6 点击确定即可
  • Chrome的Cookie的存放位置及查看方法

    Chrome的Cookie存放位置 C Users xxx AppData Local Google Chrome User Data Default Cookies实际上是一个sqlite数据库文件 可以直接打开查看 Cookie的解密参
  • C# 输入指定日期获取当前年的第一天 、当前年的最后天、某月的第一天 、某月的最后一天...

    方法 lt summary gt 取得当前年的第一天 lt summary gt lt param name 61 34 datetime 34 gt 要取得月份第一天的时间 lt param gt lt returns gt lt ret
  • centos7 和 ubuntu 安装xrdp

    centos7 和 ubuntu 安装xrdp centos7安装xrdp问题1 xrdp 找不到 ubuntu 的安装 centos7安装xrdp span class token comment 安装软件 span yum span c
  • centos7安装xrdp

    centos7安装xrdp 保证有桌面环境安装epel安装xrdp配置xrdp 保证有桌面环境 yum y span class token function groups span span class token function in
  • 在vs2017中遇到“fatal error RC1015: cannot open include file 'winres.h'.”

    解决方法 xff1a 先查找winres h所在位置 xff0c 将文件的目录位置添加到属性 VC 43 43 目录 包含目录中 xff0c 即可 类似问题亦可
  • 求一个数二进制表示法中1的个数诸多方法 .

    求一个unsigned int 数的二进制表示中有多少个1 xff1f 这是一道面试题可以用以下的一些方案 第一种是很容易想到的采用循环的方式并且与1进行位与运算 xff0c 具体代码如下 unsigned int GetBitNumOfO
  • qemu-kvm编译错误 出现 CC block/qcow2-snapshot.o

    编译qemu kvm xff0c 出现错误信息如下 xff1a CC block qcow2 snapshot o In file included from qemu common h 6 0 from block qcow2 snaps
  • Springboot基础系列:事务回滚

    1 场景 一个服务中有存在多个数据库事务 要求 保证数据一致不产生脏数据不误删数据 即前面的事务正常运行 后面的事务出现异常 数据库保持调用该服务前的状态 2 方案 Springboot开启事务 在Service实现层添加 64 Trans