幂等性
1. 幂等性是什么?
在一个系统中,一个接口,运行多次和运行一次的结果是一致的。
什么情况下需要幂等性?
重复提交、接口重试、前端窗口抖动等
业务场景:
- 用户多次点击提交订单,后台应该只生成一个订单。
- 支付时,由于发生网络问题重试,应该只扣一次钱。
保证幂等性的核心思想:通过唯一的业务单号保证幂等。
实现:
- 非并发的情况下,查询业务单号有没有操作过,没有则执行操作
- 并发的情况下,整个过程加锁
2 具体CRUD操作的幂等性
1. select操作的幂等性
查询操作天然幂等。
2 delete操作的幂等性
- 有唯一的业务号,如id。
- 第一次操作:根据唯一业务号删除
- 第二次操作:由于找不到记录,所以直接返回。可在删除前进行数据的查询。
- 没有唯一的业务号,比如将审核未通过的商品删除。
- 第一次操作:将所有审核未通过的商品删除
- 第二次操作前:又产生了新的审核未通过的商品。这时候需要根据业务需求去处理,新增的审核未通过的商品是否需要删除。
3 update操作的幂等性
update操作需要区分场景:
比如是set去更新,那么多次set不会有什么问题
如果是在当前基础上自增,那么就需要处理 ,分场景:
有唯一的业务号,如id。更新操作传入数据版本号,通过乐观锁实现。
数据库增加版本version字段,用户在查询并展示当前数据时,将version放入隐藏域。当用户点击提交时,将版本号也一同提交。
后台去判断版本号,并且进行版本号+1操作
1
update user set xxx=${xxx}, version=${version}+1 where id=xxx and version=${version}
没有唯一的业务号,比如用户登录,注册
- 采用token机制
4 insert操作的幂等性
有唯一的业务号,如秒杀场景,商品ID+用户ID。
- 解决方式:分布式锁业务执行完成后,不让锁释放,而是让其过期后释放。比如设置30s,则30s内只会有一个线程获取到锁,当用户点击多次,触发了其他线程,获取不到锁,直接返回。
没有唯一业务单号,使用token保证幂等。
具体流程
当用户进入注册页面时,后端生成一个随机token,客户端将token放在隐藏域下,带着token提交。(分布式场景下,需要类似分布式ID的处理方式,保证token唯一)
根据token去获取分布式锁,完成insert后,不让锁释放,而是让其过期后释放
1
2
3
4
5
6
7
8public int insertUser(SysUser user, String token) throws Exception {
InterProcessMutex lock = new InterProcessMutex(zkClient, "/"+token);
val isLock = lock.acquire(30, TimeUnit.SECONDS);
if(isLock){
return sysUserMapper.insert(user);
}
return 0;
}
5 混合操作的幂等性
找到操作的唯一业务单号,有则使用分布式锁,无则通过token保证
幂等性
http://example.com/幂等性/