赞
踩
说明下:这里说的接口主要指非查询类接口,因为查询类接口天然具备幂等性。
交易系统里用户下单提交订单时,由于用户连续快速点击,导致连续发送多次请求,分别命中到了不同的服务器, 那么就会生成多个内容完全相同的订单,只有订单号不同而已。
当然造成重复请求的原因,还有其他的可能:
重复请求的影响
所以接口支持幂等性非常重要,尤其是涉及交易的接口。
所谓幂等性, 通俗点说就是一个接口, 无论执行几次所产生的影响与只执行一次产生的影响是一样的。
举例子说明下:
• 支付接口, 重复支付同一笔订单,最终也只能成功扣款一次。
• 支付宝、微信支付成功回调接口, 可能会多次回调, 必须只能成功处理一次。
• 普通表单提交接口, 多次点击提交, 数据只能成功落地一次。
1. 唯一索引: 防止新增脏数据,保证最终插入数据库的数据只有一条。
2. token机制: 防止页面重复提交。
3. 悲观锁 -- 获取数据的时候加锁(一般是行锁)。
4. 乐观锁 -- 基于版本号version实现, 在更新数据那一刻校验数据。
5. 分布式锁 -- 通过第三方的系统(redis或zookeeper),在业务系统插入或更新数据时,获取分布式锁,然后做操作,最后释放锁。
解决思路:同一用户在1秒内对同一URL的操作视为重复提交。
具体步骤:
代码实现
- @PostMapping(value = "/submit-order")
- public Response<Boolean> submitOrder(HttpServletRequest request, OrderParam,orderParam){
-
- String userId= "123456";//用户
- String path = request.getServletPath();
- String key = MD5(userId+path);
-
- //1. 获取redis锁
- String result = jedis.set(key, orderParam, "NX", "EX", 1000);
- boolean success = "OK".equals(result);
- try {
- if (success) {
- //2. 执行具体业务逻辑
- //...
- }else{
- //3. 获取锁失败
- }
- } catch (Exception e) {
- e.printStackTrace();
- } finally {
- //4. 业务逻辑执行完成之后,释放锁
- jedis.del(key);
- }
-
- return ResponseUtil.success(Boolean.TRUE);
- }
其实思路很简单, 我们也可以通过拦截器(AOP)+注解的方式实现一个通用的解决方案, 就不用每次请求都写重复代码。
幂等性在设计系统时,是需要首要考虑的问题,尤其是在像银行,支付宝等互联网金融公司等涉及到钱的系统。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。