【Java】catch里面抛出了异常finally里面的事务会提交吗?

news2024/9/25 11:10:23

文章目录

  • 背景
  • 目前的代码
  • 直接实战演示
  • 单元测试
  • 总结

背景

我们公司的系统中有一个业务场景,需要第三方的账户数据同步到我们系统。
同步账号的同时,会将所有同步数据和是否成功记录到一张同步日志表中,方便排查问题和记录。
好了,话不多说,我们直接上代码。

目前的代码

下面是一段伪代码

@Data
@Build
public class Test() {
 private boolean success = true;
}


@Transaction
public void sync() {
 Test test = Test.builder().build();
 try{
  xxxxx
 }catch(Exception e) {
   log.error("xxxx",e)
   test.setSuccess(false);
   throw new ThirdAccountException("同步账号错误:" + e.getMessage());
 } finally {
   testMapper.insert(test);
 }

}

大家能看出来这段代码有什么问题吗?

直接实战演示

数据库新建 账户数据同步记录表

CREATE TABLE `account_log` (
  `id` bigint NOT NULL,
  `data` varchar(255)  DEFAULT NULL COMMENT '第三方数据',
  `success` tinyint(1) DEFAULT NULL COMMENT '是否成功0否1是',
  `error_msg` varchar(255) DEFAULT NULL COMMENT '错误信息',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

第三方账户数据实体

package com.fandf.demo.transaction;  
  
import cn.hutool.json.JSONUtil;  
import io.swagger.annotations.ApiModel;  
import lombok.AllArgsConstructor;  
import lombok.Data;  
  

@Data  
@AllArgsConstructor(staticName = "of")  
@ApiModel("第三方数据实体")  
public class ThirdAccount {  
  
    private String id;  
    private String data;  


    public AccountLog toAccountLog() {  
        return AccountLog.builder().data(JSONUtil.toJsonStr(this)).build();  
    }  
  
}

本地账户同步记录实体

package com.fandf.demo.transaction;  
  
import com.baomidou.mybatisplus.annotation.IdType;  
import com.baomidou.mybatisplus.annotation.TableId;  
import com.baomidou.mybatisplus.annotation.TableName;  
import com.baomidou.mybatisplus.extension.activerecord.Model;  
import io.swagger.annotations.ApiModelProperty;  
import lombok.Builder;  
import lombok.Data;  
import lombok.EqualsAndHashCode;  
  

@EqualsAndHashCode(callSuper = true)  
@TableName("account_log")  
@Data  
@Builder  
public class AccountLog extends Model<AccountLog> {  
  
    private static final long serialVersionUID = 5648238459610595434L;  

    @TableId(type = IdType.ASSIGN_ID)  
    private Long id;  

    @ApiModelProperty("第三方原始数据")  
    private String data;  

    @ApiModelProperty("是否成功: 0否1是")  
    private boolean success = true;  

    @ApiModelProperty("错误数据")  
    private String errorMsg;  
  
}

本地账户同步记录实体mapper

package com.fandf.demo.transaction;  
  
import com.baomidou.mybatisplus.core.mapper.BaseMapper;  
import org.springframework.stereotype.Repository;  
  

@Repository  
public interface AccountLogMapper extends BaseMapper<AccountLog> {  
}

同步账户处理的逻辑

package com.fandf.demo.transaction;  
  
import org.springframework.stereotype.Service;  
  
import javax.annotation.Resource;  
  

@Service  
public class TestTransaction {  
  
    @Resource  
    AccountLogMapper accountLogMapper;  
  
    @Transactional(rollbackFor = Exception.class)
    public void syncAccount(ThirdAccount account) {  
        AccountLog accountLog = account.toAccountLog();  
        try {  
            //模拟id为2 则抛出异常  
            if ("2".equals(account.getId())) {  
                throw new Exception("模拟抛出异常");  
            }  
        } catch (Exception e) {  
            accountLog.setSuccess(false);  
            accountLog.setErrorMsg(e.getMessage());  
            throw new IllegalArgumentException("同步第三方账号错误:" + e.getMessage());
        } finally {  
            accountLogMapper.insert(accountLog);  
        }  
    }  
  
  
}

单元测试

插入成功案例

package com.fandf.demo.transaction;  
  
import org.junit.jupiter.api.Test;  
import org.springframework.boot.test.context.SpringBootTest;  
  
import javax.annotation.Resource;  
  
import static org.junit.jupiter.api.Assertions.*;  
  
@SpringBootTest  
class TestTransactionTest {  
    @Resource  
    TestTransaction testTransaction;  
  
    @Test  
    void syncAccount() {  
        testTransaction.syncAccount(ThirdAccount.of("1", "成功数据"));  
    }  
}

查看数据库
在这里插入图片描述

是插入了,但是成功的success应该为1啊,为什么插入了0。
AccountLog.java

@ApiModelProperty("是否成功: 0否1是")  
    private boolean success = true;  

第三方转为AccountLog实体的方法

 public AccountLog toAccountLog() {  
        return AccountLog.builder().data(JSONUtil.toJsonStr(this)).build();  
    } 

我们来看看编译后的AccountLog.class源码中的AccountLogBuilder部分 success并未赋初始值

public static class AccountLogBuilder {  
    private Long id;  
    private String data;  
    private boolean success;  
    private String errorMsg;  

    AccountLogBuilder() {  
    }  

    public AccountLogBuilder id(Long id) {  
        this.id = id;  
        return this;  
    }  

    public AccountLogBuilder data(String data) {  
        this.data = data;  
        return this;  
    }  

    public AccountLogBuilder success(boolean success) {  
        this.success = success;  
        return this;  
    }  

    public AccountLogBuilder errorMsg(String errorMsg) {  
        this.errorMsg = errorMsg;  
        return this;  
    }  

    public AccountLog build() {  
        return new AccountLog(this.id, this.data, this.success, this.errorMsg);  
    }  

    public String toString() {  
        return "AccountLog.AccountLogBuilder(id=" + this.id + ", data=" + this.data + ", success=" + this.success + ", errorMsg=" + this.errorMsg + ")";  
    }  
}

我们看到Builder()方法返回了

AccountLogBuilder() {
}

对象。
指定data

public AccountLogBuilder data(String data) {  
    this.data = data;  
    return this;  
}

执行build()方法

public AccountLog build() {  
    return new AccountLog(this.id, this.data, this.success, this.errorMsg);  
}

success并未赋初始值,所以success=false, 存到数据库就是0了。
那么怎么解决呢?

  1. 字段加上注解@Builder.Default
@Builder.Default  
private boolean success = true;

我们再来测试下

@Test  
void syncAccount() {  
    testTransaction.syncAccount(ThirdAccount.of("1", "加上@Builder.Default成功数据"));  
}

查看数据库
在这里插入图片描述

插入成功。

  1. 手动赋值
 public AccountLog toAccountLog() {  
        return AccountLog.builder().success(true).data(JSONUtil.toJsonStr(this)).build();  
    } 

插入失败案例

@Test  
void syncAccount() {  
    testTransaction.syncAccount(ThirdAccount.of("2", "测试失败数据"));  
}

在这里插入图片描述

查看数据库
在这里插入图片描述

错误数据并没有插入进来。
这是因为catch里面抛出了异常,finally里面提交的事务也回滚了,我们去掉syncAccount(ThirdAccount account)方法上面的@Transactional注解。
再执行一次单元测试

@Test  
void syncAccount() {  
    testTransaction.syncAccount(ThirdAccount.of("2", "去掉@Transactional注解测试失败数据"));  
}

查看数据库
在这里插入图片描述

总结

  1. Build并不是对属性赋予默认值,如果想指定默认值可以在字段上使用@Builder.Default注解。
  2. 如果方法上加了@Transaction注解,catch里面抛出了异常,finally里面的事务会回滚。

当然我们在使用@Transaction注解的时候也需要注意事务的粒度,不能图省事直接在入口加一个Transaction注解。

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

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

相关文章

window11系统CUDA、cuDNN 安装以及环境变量配置

文章目录 一&#xff0c;说明二&#xff0c;cuda的下载以及安装1. 确定自己电脑设备哪个版本cudaa. 点击左下角b. 点击左下角c.接着点击 组件 2. cuda的下载3. cuda的安装1. 双击 点击 ok2. 同意即可3. 这个随意哪个都行4.选择安装位置 接着下一步 三&#xff0c;cuda环境变量设…

Oracle安装时先决条件检查失败和[INS-35180] 无法检查可用内存问题解决

Oracle安装时先决条件检查失败和[INS-35180] 无法检查可用内存问题解决 问题&#xff1a; [INS-13001] 此操作系统不支持 Oracle 数据库问题原因解决方案 问题2&#xff1a;[INS-35180] 无法检查可用内存问题原因解决方案 问题&#xff1a; [INS-13001] 此操作系统不支持 Oracl…

Python面向对象编程-构建游戏和GUI 手把手项目教学(1.1)

总项目目标&#xff1a;设计一个简单的纸牌游戏程序&#xff0c;称为"Higher or Lower"&#xff08;高还是低&#xff09;。游戏中&#xff0c;玩家需要猜测接下来的一张牌是比当前牌高还是低。根据猜测的准确性&#xff0c;玩家可以得到或失去相应的积分。 项目1.1…

循环码的编码、译码与循环冗余校验

本专栏包含信息论与编码的核心知识&#xff0c;按知识点组织&#xff0c;可作为教学或学习的参考。markdown版本已归档至【Github仓库&#xff1a;https://github.com/timerring/information-theory 】或者公众号【AIShareLab】回复 信息论 获取。 文章目录 循环码的编码循环码…

实现 strStr

在一个串中查找是否出现过另一个串&#xff0c;这是KMP的看家本领。 28. 实现 strStr() 力扣题目链接 实现 strStr() 函数。 给定一个 haystack 字符串和一个 needle 字符串&#xff0c;在 haystack 字符串中找出 needle 字符串出现的第一个位置 (从0开始)。如果不存在&…

七、docker-compose方式运行Jenkins,更新Jenkins版本,添加npm node环境

docker-compose方式运行Jenkins&#xff0c;更新Jenkins版本&#xff0c;添加npm node环境 一、docker-compose方式安装运行Jenkins 中发现Jenkins版本有点老&#xff0c;没有node环境&#xff0c;本节来说下更新jenkins 及添加构建前端的node环境。 1. 准备好docker-compose…

算法刷题-双指针-二分法

27. 移除元素 力扣题目链接 给你一个数组 nums 和一个值 val&#xff0c;你需要 原地 移除所有数值等于 val 的元素&#xff0c;并返回移除后数组的新长度。 不要使用额外的数组空间&#xff0c;你必须仅使用 O(1) 额外空间并原地修改输入数组。 元素的顺序可以改变。你不需…

XSS数据接收平台——蓝莲花(BlueLotus)

文章目录 一、前言二、安装三、使用1、我的JS创建一个模板2、使用创建的模板攻击3、打开攻击的目标&#xff08;这里选择pikachu靶场的存储型XSS模块测试&#xff09;4、查看返回的数据 一、前言 蓝莲花平台是清华大学曾经的蓝莲花战队搭建的平台&#xff0c;该平台用于接收xs…

【QQ界面展示-通知的发布和监听 Objective-C语言】

一、来,看看,我们先给大家介绍一下通知 1.那么,这个通知,我们就是要给大家介绍三个东西 1)一个是通知的发布:如何发布通知 2)一个是通知的监听:发布以后,如何监听通知 3)一个是通知的移除:注意,通知一定要怎么样,最后,移除, 2.当你监听了一个通知以后,当你…

【Proteus仿真】51单片机+8255A IO扩展例程

【Proteus仿真】51单片机+8255A IO扩展例程 📍相关参考:51单片机8255A扩展IO口🎬Proteus仿真演示: 📓8255A与51单片机连接 🌿51单片机的P0口作为数据总线使用,与8255A的D7~D0数据信号线进行连接,当P00 - P07不作为8255A 的A、B、C端口地址使用时,可以不接上拉电阻…

3.部署glance服务(镜像获取组件)

身份认证服务部署完毕之后&#xff0c;部署 glance 映像服务&#xff0c;映像服务可以帮助用户发现、注册、检索虚拟机镜像&#xff0c;就是说 启动实例的镜像是放在这里的 。 默认镜像存储目录为&#xff1a; /var/lib/glance/images/ controller节点 在安装和配置 glance …

lua的元表与元方法理解

元表 在 Lua 中&#xff0c;元表&#xff08;metatable&#xff09;是一种特殊的表&#xff0c;用于定义另一个表的行为。每个表都有一个关联的元表&#xff0c;通过元表可以重载表的各种操作&#xff0c;例如索引、新索引、相加等。在 Lua 中&#xff0c;元表的使用非常灵活&…

【Soft-prompt Tuning for Large Language Models to Evaluate Bias 论文略读】

Soft-prompt Tuning for Large Language Models to Evaluate Bias 论文略读 INFORMATIONAbstract1 Introduction2 Related work3 Methodology3.1 Experimental setup 4 Results5 Discussion & Conclusion总结A Fairness metricsB Hyperparmeter DetailsC DatasetsD Prompt …

Intellij IDEA设置“选中变量或方法”的背景颜色、字体颜色(Mark Occurrences)

背景 IDEA 中选中一个变量就会将所有的变量相关变量标出来&#xff0c;这样就很方便知道这个变量出现的地方。Eclipse里头把这个功能叫做 Mark Occurrences&#xff0c;IDEA 里不知道怎么称呼。 我们要解决的痛点就是提示不明显&#xff0c;如下图所示&#xff0c;Macbook这么…

RocketMQ一条消息从生产者到消费者的流程

目录 1. rocketmq 中的角色介绍 2. 一条消息从生产者到消费者的所有流程&#xff08;简版&#xff09; 3. 一条消息从生产者到消费者的所有流程 1. rocketmq 中的角色介绍 生产者 producer 生产、创造消息&#xff0c;会把消息发送到 broker 中消息代理服务 broker 负责消息…

小白怎么入门网络安全?看这篇就够啦!

由于我之前写了不少网络安全技术相关的故事文章&#xff0c;不少读者朋友知道我是从事网络安全相关的工作&#xff0c;于是经常有人在微信里问我&#xff1a; 我刚入门网络安全&#xff0c;该怎么学&#xff1f;要学哪些东西&#xff1f;有哪些方向&#xff1f;怎么选&#xff…

JVM参数配置位置+JVM参数详细配置+Visual GC 插件安装及使用,jvm分析

调优的目的是什么呢&#xff1f; 1.就是让系统更加的丝滑&#xff0c;让用户体验变得更好。 2.提升系统的性能&#xff0c;提高效率&#xff0c;充分利用jvm内存。 一.JVM参数配置位置 1.java.lang.OutOfMemoryError: Java heap space 解决方法&#xff0c;Java堆异常&#…

CSS基础学习--15 CSS布局 - Overflow

一、定义 CSS overflow 属性用于控制内容溢出元素框时显示的方式。 <!DOCTYPE html> <html> <head> <meta charset"utf-8"> <title>CSS基础学习-overflow</title> <style> #overflowTest {background: #4CAF50;color: w…

Spring基础知识(二)

目录 1.Spring Bean是什么 2.Spring提供的配置方式 3.Spring bean中的scope 4.Spring bean容器的生命周期 5.Spring的内部bean 6.Spring装配是什么 7.自动装配模式 8.自动装配的局限性 9.基于注解配置容器 10.如何启动注解装配 1.Spring Bean是什么 Spring官方文档对…

lua的用户数据的使用与c语言交互

什么是用户数据 在 Lua 中&#xff0c;用户数据&#xff08;userdata&#xff09;是一种特殊的数据类型&#xff0c;它可以用来表示外部的 C 或 C 对象&#xff0c;并将它们传递给 Lua 程序使用。用户数据是 Lua 与其他语言或系统进行交互的主要方式之一&#xff0c;它可以让 …