Java 后台防重复提交一般怎么做的?

2020-06-11 11:33:55 +08:00
 luxinfl

我们现阶段就是加了一个张表,订单号唯一主键。请求过来的时候会校验数据库有没有这条单号数据,这个方法是非事务的。还有没有什么其他好的方法了。

我在想要不要放在 redis 里面。。求大佬指教啊

12048 次点击
所在节点    Java
74 条回复
SashaMu
2020-06-11 18:25:23 +08:00
redis +1
DanielGuo
2020-06-11 18:38:28 +08:00
插入之前判重,这叫幂等——你那个订单号可能不太够,最好是由前端传入一个值作 referenceId,前端连续的重复请求都是同一 referenceId 。插入时判断数据库中有没有此 referenceId,有的话就重复,不允许插入。
防止并发插入——仅仅做了幂等也不够,若并发时也能重复插入成功。这时要做并发控制,可以在数据库层面将 referenceId 这个字段设置成唯一,由数据库阻止并发;也可以 单机的话直接 java 锁,分布式用 redis (不推荐,因为坑多)或 zookeeper 做分布式锁
qloog
2020-06-11 18:41:34 +08:00
简单点用 redis 的 set nx px 作为分布式锁来做频率控制进行处理。
luzhh
2020-06-11 18:42:27 +08:00
我之前写过一个通用的框架来保证接口的幂等性,你这个问题我讲一下大概的思路:
首先下单接口有若干个参数,n 次接口请求某几个参数值如果一样,那么认为是重复请求,那么把这几个参数拿出来组成一个在业务中可以是认为唯一的一个字符串,然后用 FutureTask 构造一个下单任务,将上面的唯一 key 和 task 保存在一个 map 中,每次请求接口时,先生成 ke 到 map 中看 value 存在不,如果存在那等待 task 的返回结果就行,如果不存在那就保存 task 到 map 中并调用 task.run 执行后续的下单业务逻辑。
这样若干个相同请求进来了只会处理一次。
上面是针对单个项目的情况,如果是集群部署的话 task 怎么保存和后面重复请求过来了怎么拿到请求结果,相应的用其他中间件改一下应该可以的。
luxinfl
2020-06-11 19:15:02 +08:00
@luzhh 这个 FutureTask 不是线程的那个吧。。。
pinkrab
2020-06-11 19:52:32 +08:00
这是一个幂等性问题,一般的处理方式有:
数据库的唯一约束,这个最简单了,但是需要看业务场景。
使用 token:提交数据的时候验证 token,一旦提交成功清除,下次来提交必会失败
状态机幂等:一个数据在整个生命周期中所经历的状态,每次进行状态校验。
mmdsun
2020-06-11 19:55:10 +08:00
网关加的过滤。同一个用户,同一个接口在 1 秒内点击了两次。就过滤掉。
opengps
2020-06-11 19:59:00 +08:00
提交时候就加 requestid,同一个 requestid 都返回同一个结果
luzhh
2020-06-11 20:08:35 +08:00
@luxinfl 就是线程相关的,通过这个可以等待并获取线程的执行结果。多个重复请求进来只有一个下单任务在执行,后续的请求直接等待结果即可。
spicecch
2020-06-11 20:28:40 +08:00
赞成 3 楼的,这个前端来判断比较方便,服务器没有返回重复提交就给他弹窗,这个前端可以判断出来的,可以去看下 xhr 的状态
Returnear
2020-06-11 20:30:17 +08:00
@Veneris 对的,严谨一点加个 3 秒过期
yukiloh
2020-06-11 21:05:13 +08:00
不需要改代码,让用户学会"风怒了,编辑"...
gaius
2020-06-12 00:44:12 +08:00
🐶参数做摘要然后分布式锁
freebird1994
2020-06-12 00:56:34 +08:00
分布式锁
Vegetable
2020-06-12 01:41:43 +08:00
后端只要做一部分就行了.

我把所有非幂等操作 md5(body+token)用 redis 做了缓存,ttl 5 秒,重复值丢弃.建立在误点操作两次请求内容完全相同的前提下能正常工作.
xcstream
2020-06-12 01:54:11 +08:00
放在 redis 里 key 就是页面生成时随机一个 id
pinktu
2020-06-12 09:16:57 +08:00
@MiBAO 好吧!以前公司重复提交都是让我加按钮设置
wupher
2020-06-12 09:17:19 +08:00
不清楚你的使用场景。

如果是业务类型,比如 A 用做 xx 操作时,禁止 A 用户同时做 xx 操作。比如不允许同时发两个密码不同的改密码请求。类似这种,比如商家转账,此时考虑用分布式锁,用数据库、Redis 、ZooKeeper 、ETCD 看你喜好和资源了。

如果是类似安全类型的,比如重放攻击。可以通过对 Nonce 串进行 Hash 校验,对于重复的请求进行识别与过滤,及至屏蔽转移攻击。
MiBAO
2020-06-12 09:18:05 +08:00
@pinktu 哈哈 我们公司不知道还好 被知道了就会和你强调这种东西一定要双向验证
guoyuchuan
2020-06-12 09:22:36 +08:00
百度一下不就知道了吗

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/680607

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX