当前位置: 首页 > wzjs >正文

地下城做解封任务的网站站长统计网站统计

地下城做解封任务的网站,站长统计网站统计,江苏网站建设怎么样,北京b2b网站开发背景 在学校的Java项目中,开发了一个文本聊天的api接口,由于当时考虑欠缺,加上调用方没有做限制,导致出现了一个用户在一秒内重复发出了多次请求的情况,从而出现了脏数据。 既然是接口重复请求了,那么就…

背景
    在学校的Java项目中,开发了一个文本聊天的api接口,由于当时考虑欠缺,加上调用方没有做限制,导致出现了一个用户在一秒内重复发出了多次请求的情况,从而出现了脏数据。


既然是接口重复请求了,那么就需要限制一个用户在一秒内只能发起一次请求。这时候就会引出一个概念【接口的幂等性】。
幂等性, 通俗的说就是一个接口, 多次发起同一个请求, 必须保证操作只能执行一次。
现实的场景如下

1. ​​订单与支付类操作​

  • ​订单创建​​:用户多次点击提交订单,需保证仅生成一个有效订单。
  • ​订单支付​​:支付接口因网络超时重试时,需确保扣款仅一次,避免重复扣款。
  • ​订单状态变更​​:如订单发货、完成等操作,重复请求需维持最终状态一致。

​示例​​:
用户支付时因网络延迟重复调用支付接口,若未做幂等,可能生成两笔扣款记录。


2. ​​资源分配与扣减​

  • ​库存扣减​​:秒杀场景中,多次请求需确保库存不被超卖。
  • ​优惠券/积分发放​​:用户领取优惠券或积分时,需防止重复领取。
  • ​账号注册​​:同一手机号或邮箱多次注册,需返回已存在的结果。

​示例​​:
库存扣减时,若重复扣减未校验幂等性,可能导致库存变为负数。


接口幂等性主要应用于 ​​可能因重复请求导致数据错误或资源冲突​​ 的业务场景,以下是典型业务操作分类:


1. ​​订单与支付类操作​

  • ​订单创建​​:用户多次点击提交订单,需保证仅生成一个有效订单。
  • ​订单支付​​:支付接口因网络超时重试时,需确保扣款仅一次,避免重复扣款。
  • ​订单状态变更​​:如订单发货、完成等操作,重复请求需维持最终状态一致。

​示例​​:
用户支付时因网络延迟重复调用支付接口,若未做幂等,可能生成两笔扣款记录。


2. ​​资源分配与扣减​

  • ​库存扣减​​:秒杀场景中,多次请求需确保库存不被超卖。
  • ​优惠券/积分发放​​:用户领取优惠券或积分时,需防止重复领取。
  • ​账号注册​​:同一手机号或邮箱多次注册,需返回已存在的结果。

​示例​​:
库存扣减时,若重复扣减未校验幂等性,可能导致库存变为负数。


3. ​​数据更新与状态流转​

  • ​状态机操作​​:如工单从“处理中”变更为“已完成”,需确保状态仅变更一次。
  • ​字段更新​​:如用户余额增减(充值、提现),需避免重复累加或扣减。
  • ​配置修改​​:系统参数调整多次提交,需保证最终值与最后一次提交一致。

​示例​​:
用户提现时接口超时重试,若未做幂等,可能多次扣减余额。


4. ​​消息队列消费场景​

  • ​消息重复消费​​:MQ因ACK失败重发消息时,需保证业务逻辑仅执行一次。
  • ​异步任务处理​​:如批量导入数据,需确保任务ID唯一,避免重复导入。

​示例​​:
订单支付成功后发送MQ通知物流系统,若消息重复消费,需避免重复创建物流单。


为了保持接口的幂等性,一般的解决方案有以下

1. ​​Token 机制(一次性令牌)​

  • ​原理​​:客户端在发起请求前先获取一个唯一Token(如UUID),服务端存储该Token(如Redis)。接口处理时校验Token是否存在,存在则执行业务并删除Token,确保仅一次有效。

2. ​​唯一索引/数据库约束​

  • ​原理​​:利用数据库的唯一索引(如订单号、业务流水号),插入重复数据时触发唯一键冲突,拦截重复请求。 
CREATE TABLE orders (id BIGINT PRIMARY KEY,order_no VARCHAR(32) UNIQUE, -- 唯一约束...
);try {orderDao.insert(order);
} catch (DuplicateKeyException e) {// 捕获重复异常,返回幂等结果
}

3. ​​状态机校验​

  • ​原理​​:业务数据具有明确状态流转(如订单从“待支付”到“已支付”),接口处理前校验状态是否允许变更。
Order order = orderDao.findById(orderId);
if (!order.getStatus().equals(Status.PENDING)) {throw new IllegalStateException("状态已更新,拒绝操作");
}

4. ​​乐观锁(版本号/时间戳)​

  • ​原理​​:在数据更新时,通过版本号或时间戳实现乐观锁,确保只有匹配当前版本的请求生效 
UPDATE table SET value = 'new', version = version + 1 
WHERE id = #{id} AND version = #{currentVersion};int rows = jdbcTemplate.update(sql, params);
if (rows == 0) {throw new OptimisticLockException("数据已被修改");
}

5. ​​分布式锁控制​

  • ​原理​​:使用分布式锁(如Redis或ZooKeeper)保证同一业务ID的请求串行处理。
String lockKey = "order_lock_" + orderId;
Boolean locked = redisTemplate.opsForValue().setIfAbsent(lockKey, "1", 10, TimeUnit.SECONDS);
if (!locked) {throw new BusyException("请勿重复提交");
}
try {// 处理业务
} finally {redisTemplate.delete(lockKey);
}

6. ​​请求去重表​

  • ​原理​​:单独维护一张去重表,记录请求的唯一标识(如业务ID + 场景),处理前先查询是否已存在。
CREATE TABLE idempotent_record (id VARCHAR(64) PRIMARY KEY, -- 业务ID + 类型created_time TIMESTAMP
);String recordId = bizId + "_" + type;
if (idempotentDao.exists(recordId)) {return; // 直接返回历史结果
}
idempotentDao.insert(recordId);

 7. ​​限流与重试策略​

  • ​辅助方案​​:通过限流(如令牌桶)降低重复请求频率,结合客户端退避重试(Exponential Backoff)减少无效调用。
  • ​工具​​:使用Guava RateLimiter或Sentinel实现限流。

由于调用方目前无法配合预请求token的动作,我这次采用的是第五种方式,采用SpringAop+redis+注解的方式来做接口限制。

注解

import java.lang.annotation.*;/***  在需要保证接口幂等性的Controller的方法上使用此注解*  重复提交校验注解*/
@Target({ElementType.PARAMETER, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ReSubmitCheck {//校验几秒内重复提交int seconds()  default 2;
}

核心逻辑,主要是通过注解+aop 的形式,在请求该接口前,先做判断,利用redis的原子操作,如果key在redis中存在,则说明在指定时间内,已经请求过了。

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;import javax.servlet.http.HttpServletRequest;
import java.util.concurrent.TimeUnit;@Aspect
@Component
@Slf4j
public class PreventReSummitAspect {/*** redis工具类*/@Autowiredprivate RedisTemplate<String, Object> redisTemplate;@Before("@annotation(reSubmitCheck)")public void preventReSubmit(JoinPoint joinPoint, ReSubmitCheck reSubmitCheck) {ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();//获取用户登录的accesstokenHttpServletRequest request = attributes.getRequest();String studentId = request.getParameter("studentId");if (studentId == null) {throw new RuntimeException("学生ID不能为空");}String senderType = StringUtils.isBlank(request.getParameter("senderType"))?"1":request.getParameter("senderType");String lockKey = "ReSubmit:" + studentId + "_" +senderType+"_"+request.getServletPath();Boolean result = redisTemplate.opsForValue().setIfAbsent(lockKey, lockKey, reSubmitCheck.seconds(), TimeUnit.SECONDS);if (!result) {System.out.println("重复请求:"+lockKey);throw new RuntimeException("重复请求:"+lockKey);}}}

使用

    @PostMapping(value = "/sendMsg")@ReSubmitCheck(seconds=2)public Result<String> sendMsg() throws IOException {}

postman测试

第一次请求



 紧接着第二次请求

 

http://www.dtcms.com/wzjs/353732.html

相关文章:

  • 做ppt比较好的网站有哪些济南新站seo外包
  • 咸宁网站建设价格百度站长平台怎么用
  • 做执法设备有哪些网站google chrome官网下载
  • wordpress 网站打开速度慢百度购物平台客服电话
  • 个人做网站外包价格如何算企业推广宣传方式
  • 网站建设培训西安如何刷app推广次数
  • p2p网贷网站建设方案赛雷猴是什么意思
  • 网站开发咨询郑州网
  • 南宁在哪里可以做网站百度信息流优化
  • 新手做导航网站数据指数
  • 网站开发做美工服务之家网站推广
  • 怎么做免费网站如何让百度收录网站优化员seo招聘
  • 如何用php数据库做网站网络服务有哪些
  • 苏州好的做网站的公司推广电话
  • wordpress 怎么修改郑州百度seo网站优化
  • 无需下载的网站百度网盘seo优化
  • 网站首页导航栏广州seo好找工作吗
  • 西安网站建设怎样友情下载网站
  • 贵阳设计公司怎么seo快速排名
  • 有没有做软件的网站佛山网站建设方案咨询
  • 网站备案备注西安seo阳建
  • 莱芜网站建设怎么样进一步优化落实
  • 网络公司给我们做的网站_但是我们不知道域名是否属于我们武汉seo优化顾问
  • 阳江房产网官网查询长沙seo行者seo09
  • 政府网站建设的理论依据发稿软文公司
  • 小红书怎么推广自己的产品优化网站内容的方法
  • 精品网站建设公司手机怎么制作网页
  • 宜兴网站优化网站检测中心
  • 个人主页网站应该怎样做怎样注册网站建立网页
  • 淄博学校网站建设方案推广策略包括哪些内容