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

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

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

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

12312 次点击
所在节点    Java
74 条回复
DJQTDJ
2020-06-11 14:13:56 +08:00
订单号不是自增的吗
wizzer
2020-06-11 14:17:24 +08:00
年月日时分秒+redis incr N 位自增长
pinktu
2020-06-11 14:19:29 +08:00
让前端写,哪边简单哪边做
wizzer
2020-06-11 14:23:52 +08:00
```
public synchronized String getNewOrderId() {
String date = DateUtil.format(new Date(), "yyMMddHHmm");
long ttl = redisService.ttl(RedisConstant.REDIS_KEY_ORDER_ID + date);
long id = 0;
if (ttl <= 0) {
id = redisService.incr(RedisConstant.REDIS_KEY_ORDER_ID + date);
redisService.expire(RedisConstant.REDIS_KEY_ORDER_ID + date, 80);
} else {
id = redisService.incr(RedisConstant.REDIS_KEY_ORDER_ID + date);
}
return date + Strings.alignRight(id, 6, '0');
}
```
jinzhongyuan
2020-06-11 14:34:35 +08:00
@luxinfl 额,不是我说的这回事吗?
zh841318441
2020-06-11 14:55:56 +08:00
后端做幂等性
一般是基于数据库方面建立唯一索引或者联合索引
基于 redis 也可以,生成订单唯一号存储在 redis 里面,保存的时候先从 reids 取,如果 reids 里面有,存储并删除。如果没有则不保存,但是这种并发情况下要考虑一下锁。
基于 token 也可以,实现情况和 redis 那种差不多.

前端:做放重复点击,点击过后没返回结果,不能重复点击.
luxinfl
2020-06-11 14:56:32 +08:00
@jinzhongyuan 就是两条完全一模一样的请求,同时进到后台了。后台要怎么处理。就这么个意思
luxinfl
2020-06-11 14:57:30 +08:00
@zh841318441 这个 token 就是上面大佬说的那种 csrf 嘛?
luxinfl
2020-06-11 14:58:23 +08:00
@hantsy 这个前端是不是只要加个隐藏的表单字段就行了。数据什么的后台生成再校验?
Veneris
2020-06-11 15:07:18 +08:00
redis 的 setnx,key 是 业务+业务 id+用户 id,set 成功则执行业务并 delete key,否则直接 return
MiBAO
2020-06-11 15:23:59 +08:00
@pinktu 思路不对呀,还是得讲究一个双向验证。
youxiachai
2020-06-11 15:27:56 +08:00
lz 是听不懂幂等是干嘛的....前面那么多人都给出标准答案了...
为啥还要前端参与....
no1xsyzy
2020-06-11 15:40:11 +08:00
你试试看 v2 在一个主题里写点东西,然后切其他标签页访问个十几分钟在其他主题下做点回复,再回到这个主题的时候点回复,会失败一次,变成一个只有回复内容的网页,需要重新点一次回复。
这个就是 CSRF,每次请求主题页面就请求一个 CSRF token,包含在 input[type="hidden"][name="once"] 里,过了有效期再发送请求的话,这个请求就会失效。
luxinfl
2020-06-11 15:50:55 +08:00
@no1xsyzy 现在是不是都流行这样搞?反正我们前台没要求我们生成个 token 给他们。。而且小公司,以前写页面的时候都是我们自己写的,也没考虑过这个。用的最多的就是 disabled
hantsy
2020-06-11 15:51:26 +08:00
@luxinfl CSRF 只对当前请求有效。重复提交后的第二次的同样的 CSRF Code 到后端是无法通过验证的。

一般传统 Web 框架都是隐藏字段,比如 JSF, Jakarta MVC 等,这些框架都是会自己有较验机制,不用手动代码检测。

https://github.com/hantsy/jakartaee-mvc-sample/blob/master/src/main/webapp/WEB-INF/views/add.xhtml#L13-L15

https://github.com/hantsy/jakartaee-mvc-sample/blob/master/src/main/java/com/example/web/TaskController.java#L89

Spring Security 也支持 Csrf,可以用于表单验证(使用 Themleaf 等),或者 Http Header (用于 API )。Spring 官方教程与 Angular 结合的 Microservice 例子,https://spring.io/guides/tutorials/spring-security-and-angular-js/
luxinfl
2020-06-11 15:52:05 +08:00
@no1xsyzy 刚才回复你的时候就碰到你说的这个情况了,跳到了一个回复页面。。是因为我改了标签属性么,加了 disabled 么。。。
hantsy
2020-06-11 15:56:23 +08:00
@luxinfl 不可能由前台,都是后台生成的。Spring Security 会默认加到 Header 上去的。
hantsy
2020-06-11 16:11:30 +08:00
Spring 官方那个例子,以前用的 Angularjs,现在换成 Angular ( 2+)了。之前 Angularjs 中 CSRF 的名字是 XSRF,Spring Security 叫 csrf, 不一致还需要转换。 现在 Angular 不用了。
hecz
2020-06-11 18:15:43 +08:00
@shenlanAZ 幂等跟锁不是一个东西。。。。
wj5868386
2020-06-11 18:23:15 +08:00
两种处理方法,后端处理,前端处理完全能绕过去的,业务层 数据库层
业务层:建立提交规则,符合规则的放行,不符合的丢弃。
数据层:锁,唯一约束。
业务层其实也就是锁的思路。

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

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

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

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

© 2021 V2EX