干货!接口中的大事务,该如何进行优化?

作为后端开发的程序员,我们常常会的一些相对比较复杂的逻辑,比如我们需要给前端写一个调用的接口,这个接口需要进行相对比较复杂的业务逻辑操作,比如会进行,查询、远程接口或本地接口调用、更新、插入、计算等一些逻辑,将最终接口的返回结果给到前端,而经过这么一系列的业务逻辑操作,接口对DB的操作、对代码业务逻辑判断、进行接口调用这些都是需要时间的,而只要这是一个事务操作,每次对数据库进行的交互都会产生一条事务记录。

那么这样就会对我们接口返回的效率产生影响,而且这个影响是随着数据量的增长而增长的,这时候我们就需要对一整个大事务进行拆分,从而提升整体接口的效率。

何为大事务

就拿我最近开发写的一个接口来说吧,大致是这么一个逻辑,我需要根据页面的提交的数据生成一个收款单,整体接口处理的业务如下,我把它们写在了一个接口里,可以理解为这是一个大事物,这个接口执行的时间是相对比较长的,而且将这些逻辑全部写在一个接口里面,本身来说也是不太合理的。

图片

大事务存在的一些问题

并发数据不一致

不加锁的情况下,由于种种原因第一次接口的调用还没执行完,还在等待第三方的调用回写数据,第二次调用又进来对数据进行了更改,第二次调用先执行完,这时候第一次接口调用拿到了第三方接口的返回,去回写状态发现已经被更新,导致无效操作。

加锁容易阻塞

加锁的情况下, 不会出现数据不一致情况,但是由于大事物执行时间较长,容易造成锁超时失效,锁定太多的数据造成阻塞,严重影响效率。

Undo logo事务日志性能问题

容易造成Undo logo日志数据量很大,降低了日志的查询性能,包括对事务的回滚效率也会降低。

并发数据库压力太大

并发量达到一定程度,会对数据库读写造成不小的压力,会堆积大量等待线程。

如何优化大事务

事务里面不要进行远程RPC调用

首先事务里面进行远程的接口调用,如果不采用分布式事务框架,本身就会存在事务不一致的情况,无法进行数据的回滚操作,并发情况下远程服务响应不及时,会出现接口返回不一致问题,当然必须采用异步调用,后面会提到。

编程型事务更加灵活

声明式事务只需要加在方法头加@Transactional注解即可开启事务,但是还是不太灵活,意味着整个方法所进行对数据库操作都要加进事务,当然一次查询也要进入事务,这并不是我们想要的,我们在update、insert操作上进行事务操作,方便进行回滚。

public Boolean transactionCommit(String userName) {//查询用户SysUser sysUser = userMapper.selectUserByUserName(userName,null);transactionTemplate.execute(new TransactionCallbackWithoutResult() {@Overrideprotected void doInTransactionWithoutResult(TransactionStatus transactionStatus) {try {if (null != sysUser) {//用户信息状态更新 status更新为1userMapper.updateStatus(userName);}} catch (Exception e){//回滚transactionStatus.setRollbackOnly();}}});//再次查询SysUser sysUser1 = userMapper.selectUserByUserName(userName,"1");/log/.info("状态为1的用户信息"+JSON./toJSONString/(sysUser1));return  true;
}

编程式事务的灵活点在于可以控制事务执行方法,运用transactionTemplate类进行事务操作,查询操作可以写在外面,这样查询获取数据的操作就不会进入mysql事务表。

数据分批处理

对于事务的更新或者插入,前端可能会有批量操作,大规模数据的批量更新、插入也会对事务接口产生影响,一旦其中有更新或插入失败,为了保证事务的一致性,整个操作都要进行回滚;

  • 前端:可以限制数据,对后端接口的访问,可以将数据进行分页,多次请求,可以避免事务提交大量数据。

  • 后端:也可以去数据进行分页处理,例如每次可以限制50条进行操作,如果是新增逻辑,使用Mybatis的批量更新大大提升效率

List<List<ReceivableFeeSaveDTO>> partition = Lists.partition(receivableFeeSaveDTOList, 50);

大事务拆分小事务

可以将一个事务接口,拆分成多个事务接口,并且每个事务接口只做一件事,比如上面的收款单生成接口,金额回写、第三方接口调用、调用后的结果回写都可以抽成一个哥小事务接口。

就好比做一件很复杂的事情,咋一眼看上去很复杂,但是我们把这复杂的步骤,进行多个步骤的拆分,每个阶段完成每个阶段的事情,就可以将整个过程简化,看起来就没那么复杂了。

异步并行处理

重中之重,事务里如果无法避免远程调用,那么肯定是需要进行异步调用,因为无法保证远程接口的及时响应性,CompletableFuture异步编排特性可以用到,task1和task2任务结束后,执行task3。

CompletableFuture<Object> task1 =CompletableFuture.supplyAsync(() -> {System.out.println("单号check线程" + Thread.currentThread().getId());//单号check接口 校验失败抛出异常return "账单实体信息";
}, executor);
CompletableFuture<Object> task2 = CompletableFuture.supplyAsync(() -> {System.out.println("收款单生成线程" + Thread.currentThread().getId());try {//收款单生成return “账单编号”;Thread.sleep(3000);System.out.println("任务2结束:");} catch (InterruptedException e) {e.printStackTrace();}}, executor);//task1、task2 执行完执行task3 ,需要感知task1和task2的执行结果
CompletableFuture<Boolean> future = task1.thenCombineAsync(task2, (t1, t2) -> {System.out.println("账单金额回写线程" + Thread.currentThread().getId());// t1 、t2返回判断//回写返回结果return ture;
}, executor);

总结

可见大事务是我们接口效率低下的罪魁祸首,有时候我们为了快速实现功能,可能会忽略一些关乎于性能的东西,而这些东西是我们能力提升的一个契机。

随着你的进步,你也许会有疑问之前为什么这么写代码,当你有这种感觉的时候,那么恭喜你,你已经站在另一个山岗,俯瞰山下一切都是那么的渺小,不多说我先去优化接口了~

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

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

相关文章

掌握iText:轻松处理PDF文档-进阶篇

简体中文写入 iText本身对简体中文的支持有限&#xff0c;但可以通过引入额外的字体包来增强其对简体中文的支持。例如&#xff0c;可以使用iTextAsian.jar这个亚洲字体包&#xff0c;它包含了几种简单的亚洲字体&#xff0c;其中包括简体中文字体。只需要将iTextAsian.jar放到…

springboot 启动之后报错:Unsatisfied dependency through field ‘bbbClient’

springboot 启动之后报错&#xff1a;UnsatisfiedDepencyException:Error creating bean with name ‘aaaServiceImpl’: Unsatisfied dependency through field ‘bbbClient’。 这两天一直在进行着日常 debugger 查看代码。可是发生了一个挺“灵异”的事件。那就是我看的项目…

46. 全排列

46. 全排列 原题链接&#xff1a;完成情况&#xff1a;解题思路&#xff1a;参考代码&#xff1a;_46全排列_构建数组回溯_46全排列_直接构建 错误经验吸取 原题链接&#xff1a; 46. 全排列 https://leetcode.cn/problems/permutations/description/ 完成情况&#xff1a;…

codeforces D.In Love

思路 用两个 m u l t i s e t multiset multiset 分别存 l , r l,r l,r 。你也可以写平衡树在 l l l 的 m u l t i s e t multiset multiset 里去查询是否存在比最小的 r r r 大的 l l l 。 Think Twice, Code Once #include<bits/stdc.h> #define il inline #d…

小模型学习(1)-人脸识别

【写作背景】因为最近一直在研究大模型&#xff0c;在与客户进行交流时&#xff0c;如果要将大模型的变革性能力讲清楚&#xff0c;就一定要能将AI小模型的一些原理和效果讲清楚&#xff0c;进而形成对比。当然这不是一件简单的事情&#xff0c;一方面大模型分析问题的的本质原…

Mybatis分页插件PageHelper

PageHelper是什么&#xff1f; 是MyBatis提供的分页插件&#xff0c;可以支持MySQL、Oracle等六种数据库。 集成方式如下&#xff1a; 1 引入依赖 <!-- https://mvnrepository.com/artifact/com.github.pagehelper/pagehelper --> <dependency><groupId>co…

反射加载SDK完成统一调用

文章目录 1、需求背景2、接口抽象类具体实现类3、疑问4、存在的问题5、通过反射加载SDK并完成调用5、补充&#xff1a;关于业务网关7、补充&#xff1a;关于SDK的开发 关键点&#xff1a; 接口抽象类&#xff08;半抽象半实现&#xff09;具体实现类业务网关反射加载SDK&#…

JAVA如何调用python

以下代码想通过测试&#xff0c;必须有一个前提&#xff1a;电脑上安装了Python环境。不太习惯说废话&#xff0c;直接上代码了。 以下是用于测试的python代码&#xff08;mytest.py&#xff09;&#xff1a; # 因为用户到了参数处理&#xff0c;所以需要引用 import argpars…

Java学习手册——第五篇数据类型

数据类型&#xff1a;是数据化的基石&#xff0c;如果没有数据类型怎么表示呢&#xff1f;比如年龄可以用整数&#xff1a;18岁。如果有更好的表示方式大家可以留言哟~ 在举个例子就是姓名&#xff0c;我们需要用字符串的形式来表示。这就是数据类型的魅力&#xff0c;而又有同…

TS基础语法

前言&#xff1a; 因为在写前端的时候&#xff0c;发现很多UI组件的语法都已经开始使用TS语法&#xff0c;不学习TS根本看不到懂&#xff0c;所以简单的学一下TS语法。为了看UI组件的简单代码&#xff0c;不至于一脸懵。 一、安装node 对于windows来讲&#xff0c;node版本高…

电脑出现这些现象,说明你的固态硬盘要坏了

与传统机械硬盘&#xff08;HDD&#xff09;相比&#xff0c;固态硬盘&#xff08;SSD&#xff09;速度更快、更稳定、功耗更低。但固态硬盘并不是完美无瑕的&#xff0c;由于颗粒写入机制&#xff0c;可能会在七到十年的预期寿命之前出现故障。所以用户最好为最终故障做好准备…

网页设计中增强现实的兴起

目录 了解增强现实 增强现实的历史背景 AR 和网页设计的交叉点 AR 在网页设计中的优势 增强参与度和互动性 个性化的用户体验 竞争优势和品牌差异化 AR 在网页设计中的用例 结论 近年来&#xff0c;增强现实已成为一股变革力量&#xff0c;重塑了我们与数字领域互动的方式。它被…

【FMCW毫米波雷达设计 】 — FMCW波形

原书&#xff1a;FMCW Radar Design 1 引言 本章研究驱动FMCW雷达的主要波形:线性调频(LFM)波形。我们研究信号的行为及其性质。随后&#xff0c;本章讨论了匹配滤波理论&#xff0c;并研究了压缩这种波形的技术&#xff0c;特别是所谓的拉伸处理&#xff0c;它赋予FMCW雷达极…

DOS 批处理 (二)

DOS 批处理 1. 基础 DOS 命令1.1 基础命令1.2 文件系统操作1.3 文件夹管理1.4 文件管理1.5 网络相关1.6 系统管理1.7 IF、FOR和NETIFFORNET 1. 基础 DOS 命令 command /? 查找帮助DOS命令不区分命令字母的大小写 C:\Users\Administrator>echo 1 1 C:\Users\Administrator…

基于SSM框架的仓库管理系统

基于SSM框架的仓库管理系统 文章目录 基于SSM框架的仓库管理系统 一.引言二.系统设计三.技术架构四.功能实现五.界面展示六.源码获取 一.引言 现代商业环境中&#xff0c;仓库管理对于企业的运营效率和客户满意度至关重要。传统的手工管理方式已经无法满足日益复杂的仓储需求。…

【Spring】SpringBoot日志

SpringBoot日志 日志概述日志使用打印日志获取日志对象使用日志对象打印日志日志框架介绍门面模式SLF4J框架介绍(simple logging facade for java) 日志格式说明日志级别日志级别的分类日志级别的使用 日志配置配置日志级别日志持久化配置日志文件的路径和文件名配置日志文件的…

【刷题篇】动态规划(六)

文章目录 1、最大子数组和2、环形子数组的最大和3、乘积最大子数组4、乘积为正数的最长子数组长度5、 等差数列划分6、最长湍流子数组 1、最大子数组和 给你一个整数数组 nums &#xff0c;请你找出一个具有最大和的连续子数组&#xff08;子数组最少包含一个元素&#xff09;&…

【Unity动画】Avatar Mask

创建 Avatar Mask可以设置那一部分骨骼运动和不运动 然后放在状态机里面的层中来混合 【后续完善】

深入探索 Rust 宏编程

Rust 宏提供了一种强大的方法来编写抽象和重用代码,它们在 Rust 编程中扮演着重要的角色。本文将深入探索 Rust 宏的概念、类型、使用方法以及如何实现自定义宏,以提供一个全面的 Rust 宏编程指南。 Rust 宏简介 宏是 Rust 中的一种元编程工具,它们在编译时运行,用于生成…

linux安装node

文章目录 安装node 安装node 一次手操记录 - 首先安装wget yum install -y wget - 下载nodejs最新的tar包 wget https://cdn.npm.taobao.org/dist/node/v12.12.0/node-v12.12.0-linux-x64.tar.xz - 解压包 tar -xvf node-v12.12.0-linux-x64.tar.xz - 部署bin文件 先确认你no…