谈谈如何确保数据的一致性

2023-05-16

谈谈如何确保数据的一致性

  • 数据库必须具备的四个特性
  • 背景
  • 什么是接口的幂等性?
  • 幂等性在哪里会用到?
  • 技术方案
  • 总结

参考https://blog.csdn.net/u011635492/article/details/81058153

数据库必须具备的四个特性

1:原子性:事务包含的所有操作要么全部成功,要么全部失败回滚;成功必须要完全应用到数据库,失败则不能对数据库产生影响;
2:一致性:事务执行前和执行后必须处于一致性状态,
例:用户A和用户B的前加起来一共是5000; 无论AB用户之间是如何相互转换的,事务结束后两个用户的钱加起来还是5000,这就是事务的一致性。

3:隔离性:当多个用户并发访问数据库时,数据库为每一个用户开启的事务,不被其他事务的操作所干扰,多个并发事务之间要相互隔离;

4:持久性:一个事务一旦被提交了,那么对数据库中的数据的改变就是永久性的,即便在数据库系统遇到故障的情况下也不会丢失事物的操作。

背景

最近一个金融项目上线后出现了严重的车祸现场,用户资产数据出现脏数据(资产负数,一笔订单变成四笔订单,平白无故多出的钱)。随后根据数据库一一排查:
1.前端重复提交选中的数据,后台产生可能后产生多个响应结果,数据不能保持一致性。
2.用户发起一笔付款请求,如果遇到网络超时,同一个请求重复发送多次,可能造成用户账号多次扣款。
3.创建业务订单时,一次业务请求可能会产生多个订单。
所以保持接口的幂等性很重要。

什么是接口的幂等性?

数学上的定义是f(f(x))=f(x),x被函数f作用了一次或无数次的结果都是一样的。
在软件系统中定义是,当一个函数或一个接口被相同的参数调用一次或无数次结果都是一致的。
我们也可以说是确保数据的一致性。

幂等性在哪里会用到?

1.前端重复提交选中的数据,后台应该只产生对应本次提交的一个响应结果。
2.用户发起一笔付款请求,应该只扣除用户账号一次钱,即使遇到网络重发或系统bug重发是,也只扣除一次钱。
3.创建业务订单是,一次业务请求只能创建一个订单。

技术方案

  1. 唯一索引,防止新增脏数据。比如:支付宝的资金账户,支付宝也有用户账户,每个用户只能有一个资金账户,怎么防止给用户创建资金账户多个,那么给资金账户表中的用户ID加唯一索引。以支付为例,在不考虑并发的情况下,实现幂等很简单:①先查询一下订单是否已经支付过;②如果已经支付过,则返回支付成功;如果没有支付,进行支付流程,修改订单状态为‘已支付’。要点:唯一索引或唯一组合索引来防止新增数据存在脏数据(当表存在唯一索引,并发时新增报错时,再查询一次就可以了,数据应该已经存在了,返回结果即可);

  2. token机制,防止页面重复提交。业务要求: 页面的数据只能被点击提交一次;发生原因: 由于重复点击或者网络重发,或者nginx重发等情况会导致数据被重复提交;解决办法: 集群环境采用token加redis(redis单线程的,处理需要排队);单JVM环境:采用token加redis或token加jvm内存。处理流程:1. 数据提交前要向服务的申请token,token放到redis或jvm内存,token有效时间;2. 提交后后台校验token,同时删除token,生成新的token返回。token特点:要申请,一次有效性,可以限流。注意:redis要用删除操作来判断token,删除成功代表token校验通过,如果用select+delete来校验token,存在并发问题,不建议使用;
    悲观锁——获取数据的时候加锁获取。select * from table_xxx where id=‘xxx’ for update; 注意:id字段一定是主键或者唯一索引,不然是锁表,会死人的悲观锁使用时一般伴随事务一起使用,数据锁定时间可能会很长,根据实际情况选用;

  3. 悲观锁——获取数据的时候加锁获取。select * from table_xxx where id=‘xxx’ for update;
    注意:id字段一定是主键或者唯一索引,不然是锁表,会死人的悲观锁使用时一般伴随事务一起使用,数据锁定时间可能会很长,根据实际情况选用;

  4. 乐观锁——每次去拿数据的时候,都认为别人不会修改,不会加锁,但在更新的时候会去判断一下,此期间别人有没有更新数据,版本号机制和CAS算法就用到乐观锁,所以相对于悲观锁,效率更高。乐观锁的实现方式多种多样可以通过version或者其他状态条件:

    • 通过版本号实现update table_xxx set name=#name#,version=version+1 where
      version=#version#;
    • 通过条件限制 update table_xxx set avai_amount=avai_amount-#subAmount# where avai_amount-#subAmount# >=0要求:quality-#subQuality# >=
      ,这个情景适合不用版本号,只更新是做数据安全校验,适合库存模型,扣份额和回滚份额,性能更高;但是,乐观锁存在失效的情况,就是常说的ABA问题。如果version版本一直是自增的就不会出现ABA的情况。
      参考——乐观锁版本号机制值CAS:https://www.cnblogs.com/cwb123/articles/10847043.html
      拓展——CAS下ABA问题及优化方案:https://mp.weixin.qq.com/s/xMoQk99N2gyz7ftBfcTLGQ
  5. 分布式锁——还是拿插入数据的例子,如果是分布式系统,构建全局唯一索引比较困难,例如唯一性的字段没法确定,这时候可以引入分布式锁,通过第三方的系统(redis或zookeeper),在业务系统插入数据或者更新数据,获取分布式锁,然后做操作,之后释放锁,这样其实是把多线程并发的锁的思路,引入了多个系统,也就是分布式系统中得解决思路。要点:某个长流程处理过程要求不能并发执行,可以在流程执行之前根据某个标志(用户ID+后缀等)获取分布式锁,其他流程执行时获取锁就会失败,也就是同一时间该流程只能有一个能执行成功,执行完成后,释放分布式锁(分布式锁要第三方系统提供);

  6. select + insert——并发不高的后台系统,或者一些任务JOB,为了支持幂等,支持重复执行,简单的处理方法是,先查询下一些关键数据,判断是否已经执行过,在进行业务处理,就可以了。注意:核心高并发流程不要用这种方法;

  7. 状态机幂等——在设计单据相关的业务,或者是任务相关的业务,肯定会涉及到状态机(状态变更图),就是业务单据上面有个状态,状态在不同的情况下会发生变更,一般情况下存在有限状态机,这时候,如果状态机已经处于下一个状态,这时候来了一个上一个状态的变更,理论上是不能够变更的,这样的话,保证了有限状态机的幂等。注意:订单等单据类业务,存在很长的状态流转,一定要深刻理解状态机,对业务系统设计能力提高有很大帮助 。

  8. 对外提供接口的api如何保证幂等。如银联提供的付款接口:需要接入商户提交付款请求时附带:source来源,seq序列号 。

  9. source+seq在数据库里面做唯一索引,防止多次付款(并发时,只能处理一个请求)
    。重点:对外提供接口为了支持幂等调用,接口有两个字段必须传,一个是来源source,一个是来源方序列号seq,这个两个字段在提供方系统里面做联合唯一索引,这样当第三方调用时,先在本方系统里面查询一下,是否已经处理过,返回相应处理结果;没有处理过,进行相应处理,返回结果。注意,为了幂等友好,一定要先查询一下,是否处理过该笔业务,不查询直接插入业务系统,会报错,但实际已经处理了。

  10. 支付缓冲区:把订单的支付请求都快速地接下来,一个快速接单的缓冲管道。后续使用异步任务处理管道中的数据,过滤掉重复的待支付订单。优点是同步转异步,高吞吐量。缺点是不能及时地返回支付结果,需要后续监听支付结果的异步返回。

总结

接口的幂等性处理与数据设计,业务流程有着密切关联,像资产,钱包,交易所,这些都是与钱打交道的,数据的安全,准确还有一致性更要谨慎,如果处理不好会影响用户体验度。

  • 接口开发时,要对异常参数进行校验,对于一些不可逆的操作,操作之前一定要让用户再确认一遍,比如删除订单,转账等…
  • 对于账户资产的操作,该加事务、乐观锁的地方都加上,高并发时是很可能出现问题: 账户划转,连续划转,转出账户扣一次钱,转入账户加两次钱
    1. 取消订单,订单取消成功,但是冻结金额直接没了,没加回到可用金额里面 对于数据校验的顺序问题
    2. 用户下单,生成订单前检验了余额,这时候打个断点,在另一个浏览器登录这个账号 ,再次下单,这时放开第一个订单的断点,会生成两个订单
  • 注意数据库记录的时间,不插入时间的,调用时就会显示1970-01-0100:00:00,或者插
    了服务器本地时间的,如果服务器是国外的,数据就错误了
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

谈谈如何确保数据的一致性 的相关文章

  • Linux系统下使用rpm安装时失败 出现错误:“依赖检测失败” 解决方法

    今天长青在重新安装yum的时候出现了这种错误 xff0c 提示 依赖检测失败 解决方法 xff1a 在命令末尾加上 nodeps force 参数意思 xff1a nodeps xff1a 不检测依赖关系 force xff1a 强制安装
  • springboot的sql日志打印与AOP实现接口调用日志打印

    Springboot的sql日志打印与AOP实现接口调用日志打印 96 1 Springboot与mybatis或者mybatisplus 打印sql执行语句 使用的是springboot中内部嵌入的日志框架 2 接口调用日志 xff0c
  • 双一流博士整理的71个OpenCV实战项目教程开放下载!

    点击上方 小白学视觉 xff0c 选择加 34 星标 34 或 置顶 重磅干货 xff0c 第一时间送达 近期小白学视觉公众号推出了多篇Python 43 OpenCV实战项目的文章 xff0c 深受小伙伴们的喜爱 最近有小伙伴推荐 xff
  • 资料分析之增长量

    一 增长量的计算 识别 xff1a 增长 43 单位 公式 xff1a 1 给出现期 基期 xff1a 增长量 61 现期 基期 2 给出现期 增长率 xff1a 增长量 61 r 现期 1 43 r 速算 xff1a 1 尾数法法 xff
  • Manjaro 基础配置及常用软件安装

    更新源 获取key https mirrors tuna tsinghua edu cn help archlinux https mirrors tuna tsinghua edu cn help archlinuxcn 安装常用工具 x
  • JS中new Date().format("YYYY-mm-dd")提示format is not a function的解决办法

    format方法已经被移除了 xff0c 赶快换个组件 xff01 如果是个懒人 xff0c 就不要再看那些自己写方法大神给的函数了 xff01 xff01 用moment xff0c npm一下子就能装好 xff0c 很好用 xff01
  • python去掉字符串中的指定字符的方法

    我们在使用 Python处理字符串的时候 xff0c 经常会遇到一些字符串中出现了指定字符 xff0c 比如以下代码 xff1a 上面代码中的 就是一个指定字符 xff0c 在 python中 xff0c 如果使用 替换为指定字符 xff0
  • linux使用yum安装JDK8

    安装步骤 xff1a 1 查看是否已安装JDK yum list installed span class token operator span grep java 2 卸载CentOS系统Java环境 yum span class to
  • 图像的边缘检测和缺失修复(附matlab代码)

    最近在数学建模过程中老师给了个图片分别在清晰 有噪声及模糊状态下对其进行边缘检测的题目 xff0c 最后一题是将图片中一部分抠出后将图片按照剩余图片的特征进行修复 xff0c 整个问题涉及到人工智能及计算机视觉的领域较多 xff0c 和队友
  • FileNotFoundError:[Errno 2] No such file or directory :

    FileNotFoundError Errno 2 No such file or directory 1 根本原因 xff1a 路径有问题 2 可能的原因 xff1a 1 xff09 注意Windows与Linux分隔符的区别 Windo
  • Python学习-使用matplotlib画动态多图

    近期经常使用matplotlib进行数学函数图的绘制 xff0c 但是如何使用matplotlib绘制动态图 xff0c 以及绘制动态多图 xff0c 直到今天才学会 1 参考文字 首先感谢几篇文字的作者 xff0c 帮我学会了如何绘制 x
  • VS Code:无法在终端运行命令的解决方法

    1 在VSCode配置好 java 的开发环境后 xff0c 在终端运行时出现如下错误 xff1a 2 刚开始以为是系统环境没配置好 xff0c 结果在 PowerShell 运行没问题 xff1a 3 网上找到了解决方法 xff0c 原因
  • 应用宝sdk跳坑之路 - 1

    这次接入的是ysdk加midas的客户端下单模式 第一次接ysdk xff0c 卡住情况是在对接人员不搭理情况下 登录 0 qq登录未设置调试者账号 和 微信登录签名对不上的就不说了 1 登录的时候返回码一直是3100 xff0c 您尚未登
  • vscode本地同步修改ftp服务器文件

    这里写自定义目录标题 vscode本地同步修改ftp服务器文件搜索插件插件设置本地修改与服务器文件同步 vscode本地同步修改ftp服务器文件 本文记录一下本人使用vscode成功连接远程ftp服务器 xff0c 并成功修改文件的步骤 搜
  • docker拉命令时报错 ERROR: Get https://registry-1.docker.io/v2/: net/http: TLS handshake timeout

    报错 xff1a 关于pull 命令时报错 xff1a get https registry 1 docker io v2 ner http TLS handshake timeout 或者 request canceled while w
  • 2018年App测试流程及要点梳理

    先说说 xff0c 为什么要给大家梳理App测试流程和要点呢 xff1f 主要是缘于有太多同学咨询相关App测试的问题 xff0c 回答的次数多了 xff0c 就不想打字了 xff0c 还不如这样全部帮你们整理好 xff0c 希望各位看到的
  • Java使用FTP时碰到的坑--服务部署到linux时storeFile返回false

    背景 正常情况下 xff0c 我们都是把上传的文件保存到Java服务运行的服务器上 前段时间根据公司正式环境上的情况 xff0c 必须要把文件做成跨服务器存储 xff0c 经过考虑 xff0c 最终采用FTP工具存储文件 因为保存的文件并不
  • 安装了VMwaretools却无法使用

    在很早之前安装了VMwaretools却无法使用 xff0c 不能实现在windows以及ubuntu互相之间的复制粘贴 今天想着彻底解决一下这个问题 xff0c 进行了一番操作 刚开始看到有博主说因为Ubuntu的次怕空间不足了 xff0
  • Java去掉数字字符串开头的0 四种方法 000010

    推荐方法一 方式一 xff1a String str 61 34 000010 34 int result 61 Integer parseInt tempStr System out println result 输出 xff1a 10

随机推荐

  • Ubuntu apt 安装gedit,报错 E: Unable to correct problems, you have held broken packages.

    Ubuntu apt 安装gedit xff0c 报错 E Unable to correct problems you have held broken packages 在安装软件的时候报错 xff1a 网上查询了很多资料 xff0c
  • rhel 7 yum源错误提示以及解决方式

    在 etc yum repos d 写好 repo 执行yum repolist之后出现以下错误提示 This system is not registered with an entitlement server You can use
  • C++——三种继承方式与三种访问权限的相互组合

    三种访问权限 public 可以被任意实体访问 protected 只允许子类及本类的成员函数访问 private 只允许本类的成员函数访问 三种继承方式 public 继承 protect 继承 private 继承 组合结果 基类中 继
  • Maven setting.xml国内镜像仓库(全)

    打开setting xml 位置在apache maven 3 6 1 conf下面 Ctrl 43 F 查找mirror标签位置加入即可 lt maven官方镜像 gt lt mirror gt lt id gt mirrorId lt
  • Android Studio创建项目

    一 创建新项目 二 选择空白页项目类型 三 设置项目信息 四 下载SDK 只有初次创建时会下载 下载完成 五 初始化项目工程 初始化完成
  • 解决MATLAB"尝试将 SCRIPT open 作为函数执行"的问题

    解决MATLAB 34 尝试将 SCRIPT open 作为函数执行 34 的问题 当关闭MATLAB一个脚本的时候 xff0c 再次双击打开 xff0c 会出现下图的情况 xff1a 脚本无法打开 xff0c 只能用实时脚本的方式打开 x
  • SMM(Spring+SpringMVC+MyBatis)

    Spring amp SpringMVC amp MyBatis 一 Spring的体系结构 自下往上 xff1a TestCore Container 核心容器 Beans xff1a 容器Core xff1a 核心Context xff
  • 二、SpringBoot基础配置

    二 SpringBoot基础配置 二 SpringBoot基础配置1 复制工程2 属性配置3 配置文件分类3 1 配置文件优先级3 2 教你一招 xff1a 自动提示功能消失解决方案 4 yaml文件5 yaml数据读取5 1 读取单一数据
  • FSK和ASK区别

    简介 市面上的遥控器常见的有FSK和ASK两种 xff0c 一种是有应答 xff0c 一种无应答 xff0c 现将主要区别罗列如下 FSK和ASK区别 FSK xff1a 频率调制 ASK xff1a 振幅调制 ASK IC一般只发射不接受
  • 关闭集群机器命令脚本

    背景 没有脚本时 xff0c 关闭集群里的Linux机器 xff0c 需要分别在每台机器执行关机命令 xff0c 费时费力 hadoop 64 node2 sudo init 0 hadoop 64 node3 sudo init 0 ha
  • ubuntu系统如何建立可执行文件

    第一步 xff1a 在桌面建立一个新建文档 gt 空文件 xff0c 文档重命名为test txt 第二步 xff1a 打开test txt xff0c 在文档的最顶端写入 bin bash xff08 独占一行 xff09 如 xff1a
  • 自己动手写操作系统(高清图书+源代码)分享

    很喜欢 自己动手写操作系统 这本书 xff0c 但现在这本书已经绝版了 在这里分享一下这本书的高清电子版和源代码 xff0c 感兴趣的人可以下载一下 链接 xff1a https pan baidu com s 1lPXg Airu2NFj
  • Android Studio闪屏页

    现在很多 App 启动都有闪屏页和功能引导页 xff0c 那么接下来我们就来先看看闪屏页是怎么实现的吧 首先创建一个新的工程 xff0c 然后创建一个新的Empty Activity xff0c 在这我就命名为SplashActivity
  • layui图标显示方框

    解决方法 检查一下class里面是不是少了一个图标的默认class layui icon
  • win10下python代码打包成exe文件并作为服务后在后台运行,开机自启

    1 pip安装pyinstaller pip install pyinstaller 2 打包python文件 打开cmd xff0c cd到项目文件夹 xff0c 并将主文件 xff08 我这里是web py xff09 用pyinsta
  • ubuntu为软件设定图标

    第一步 xff1a 进入到usr share applications 文件夹下 cd usr share applications 第二步 xff1a 创建桌面图标 xff1a sudo touch clion desktop 第三步 x
  • ubuntu18.04.1 开机默认进入命令行模式/用户图形界面

    一 开机默认进入命令行模式 1 输入命令 xff1a sudo systemctl set default multi user target 2 重启 xff1a reboot 要进入图形界面 xff0c 只需要输入命令startx 从图
  • ftp上传图片损坏怎么办?

    ftp不适用于普通的传输文件 xff0c 必须使用二进制的传输格式才可以保证图片上传不被损坏 添加这两行代码即可 xff01
  • python基础-古诗词填词游戏

    很久没写爬虫了 xff0c 利用这次接单来顺便写一下爬虫 文章目录 1 项目需求2 思路梳理3 诗句处理遇到的问题有4 目录结构5 实现步骤6 收获7 不足 1 项目需求 用python实现古诗词填词游戏 诗词库的组成 初中古诗 备注 xf
  • 谈谈如何确保数据的一致性

    谈谈如何确保数据的一致性 数据库必须具备的四个特性背景什么是接口的幂等性 xff1f 幂等性在哪里会用到 xff1f 技术方案总结 参考https blog csdn net u011635492 article details 81058