苏眠月|写一个通用的幂等组件,我觉得很有必要

本文目录

  1. 背景
  2. 简单幂等实现
2.1 数据库记录判断
2.2 并发问题解决
  1. 通用幂等实现
3.1 设计方案
3.1.1 通用存储
3.1.2 使用简单
3.1.3 支持注解
3.1.4 多级存储
3.1.5 并发读写
3.1.6 执行流程
3.2 幂等接口
3.3 幂等注解
3.4 自动区分重复请求
3.5 存储结构
3.6 源码地址
背景回答群友的问题:幂等有没有什么通用的方案和实践?
关于什么是幂等 , 本文就不再阐述了 。 相信大家都知道 , 并且也都遇到过类似的问题以及有自己的一套解决方案 。
基本上所有业务系统中的幂等都是各自进行处理 , 也不是说不能统一处理 , 统一处理的话需要考虑的内容会比较多 。
我个人认为核心的业务还是适合业务方自己去处理 , 比如订单支付 , 会有个支付记录表 , 一个订单只能被支付一次 , 通过支付记录表就可以达到幂等的效果 。
还有一些不是核心的业务 , 但是也有幂等的需求 。 比如网络问题 , 多次重试 。 用户点击多次等场景 。 这种场景下还是需要一个通用的幂等框架来处理 , 会让业务开发更加简单 。
简单幂等实现幂等的实现其实并不复杂 , 方案也有很多种 , 首先介绍下基于数据库记录的方案来实现 , 后面再介绍通用方案 。
数据库记录判断以文章开头讲的支付场景来举例 。 业务场景是一个订单只能支付一次 , 所以我们在支付之前会判断这个订单有没有支付过 , 如果没有支付过则进行支付 , 如果支付过了 , 就反正支付成功 , 幂等 。
这种方式需要有一个额外的表来存储做过的动作 , 才能判断之前有没有做过这件事情 。
就好比你年龄大了 , 然后还是单身的技术宅 。 这个时候你家里着急了呀 , 你老妈天天给你介绍小姐姐 。 你每个周末都要打扮的非常帅气 , 去见你老妈给你介绍的小姐姐 。
去之前你得记录下吧 , 8 月第一周我见的 XXX, 第二周我见的 YYY, 如果第三周又让你去见 XXX, 如果这个时候你不喜欢 XXX, 你会翻出你的小本本看下 , 这个之前见过了 , 没必要再见了 , 不然见了多尴尬啊 。
并发问题解决通过查询支付记录 , 判断能否进行支付在业务逻辑上没一点问题 。 但是在并发场景就会有问题 。
1001 的订单发起了两次支付请求 , 当前两个请求同时查询支付记录 , 都没有查询到 , 然后都开始走支付的逻辑 , 最后发现同一个订单支付了两次 , 这就是并发导致的幂等问题 。
并发解决的方案也有很多种 , 简单点的直接用数据库的唯一索引解决 , 稍微麻烦点的都会用分布式锁来对同一个资源进行加锁 。
比如我们对订单 1001 进行加锁 , 如果同时发起了两次支付请求 , 那么同一时间只能有一个请求可以获取锁 , 另一个请求获取不到锁可以直接失败 , 也可以等待前面的请求执行完成 。
如果等待前面的请求执行完成 , 接着往下处理 , 就能查到 1001 已经支付过了 , 直接返回支付成功了 。
通用幂等实现为了能够让大家更专注于业务功能的开发 , 简单场景的幂等操作我认为可以进行统一封装来处理 , 下面介绍一下通用幂等的实现 。
苏眠月|写一个通用的幂等组件,我觉得很有必要SJwxerVeyL7CyOr0.png
设计方案通用存储【苏眠月|写一个通用的幂等组件,我觉得很有必要】一般我们在程序内部做幂等的话都是先查询 , 然后根据查询的结果做对应的操作 。 同时会对相同的资源进行加锁来避免并发问题 。
加锁是通用的 , 不通用的部分就是判断这个操作之前有没有操作过 , 所以我们需要有一个通用的存储来记录所有的操作 。


推荐阅读