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

网站自适应屏幕电子商务与网站建设策划书

网站自适应屏幕,电子商务与网站建设策划书,如何做招聘网站效果分析,如何自创软件背景 在学校的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/a/612536.html

相关文章:

  • 网站开辟两学一做专栏wordpress放在哪
  • 河北廊坊建设局网站网站建设的要点是什么意思
  • 程序可以做网站吗ps网站建设教程
  • 邢台移动网站建设广告设计海报
  • 网站右侧虚代码南宁网络营销网站
  • 建设网站需要申请报告网站空间有什么用
  • 商城网站项目策划书天河网站 建设信科网络
  • 苏州那家公司做网站好曹县网站建设公司
  • 昆明集团网站建设推广普通话作文
  • 站长之家工具查询企业网站营销常用的方法
  • 做网站制作外包苏州钻木网络科技有限公司
  • 网站部分网页乱码视频发布网站有哪些内容
  • 商业网站的后缀网站建设标准
  • 模版建站做公司网站哪家好 上海
  • 企业网站建立费用 作什么科目国外优秀app设计网站
  • 网站开发设计论文商业图片素材网站
  • 做国际贸易做什么网站广州网页设计师
  • 泰州网站开发万网网站后台管理系统
  • asp网站后台安全退出佛山城市建设投资有限公司
  • 网站报纸什么软件做上海做网站报价
  • 电商网站首页模板网站建设伍金手指下拉6
  • 奇葩网站100个濮阳网络教育
  • 北京市城乡建设协会官方网站商城网站建设视频教程
  • 免费领手机 网站网站开发设计资讯
  • 个人网站备案后可以做行业内容吗岳阳网站建设公司
  • 财政局网站建设自查报告闽侯网站建设
  • 上饶做网站建设idc 网站备案
  • 商城设计方案广州seo代理计费
  • 南通网站制作多语言企业网站
  • 常州制作网站软件外国域名注册很多网站