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

网站建设的3个基本原则百度权重批量查询

网站建设的3个基本原则,百度权重批量查询,用香港阿里云做网站好有钱,开发网站步骤当用户发起请求,此时会请求nginx,nginx会访问到tomcat,而tomcat中的程序,会进行串行操作,分成如下几个步骤 1、查询优惠卷 2、判断秒杀库存是否足够 3、查询订单 4、校验是否是一人一单 5、扣减库存 6、创建订单…

当用户发起请求,此时会请求nginx,nginx会访问到tomcat,而tomcat中的程序,会进行串行操作,分成如下几个步骤

1、查询优惠卷

2、判断秒杀库存是否足够

3、查询订单

4、校验是否是一人一单

5、扣减库存

6、创建订单

在这六步操作中,又有很多操作是要去操作数据库的,而且还是一个线程串行执行, 这样就会导致我们的程序执行的很慢,所以我们需要异步程序执行

思路:

当用户下单之后,判断库存是否充足只需要到redis中去根据key找对应的value是否大于0即可,如果不充足,则直接结束,如果充足,继续在redis中判断用户是否可以下单,如果set集合中没有这条数据,说明他可以下单,如果set集合中没有这条记录,则将userId和优惠卷存入到redis中,并且返回0,整个过程需要保证是原子性的,我们可以使用lua来操作

当以上判断逻辑走完之后,我们可以判断当前redis中返回的结果是否是0 ,如果是0,则表示可以下单,则将之前说的信息存入到到queue中去,然后返回,然后再来个线程异步的下单,前端可以通过返回的订单id来判断是否下单成功

执行lua脚本 用redis判断购买资格  0则表示用户有资格 消息已经发出

-- 1、参数列表
-- 优惠卷id
local voucherId = ARGV[1]
-- 用户id
local userId = ARGV[2]
-- 订单id
local orderId = ARGV[3]-- 2、数据key
-- 库存key
local stockKey = 'seckill:stock:' .. voucherId
-- 订单key
local orderKey = 'seckill:order:' .. voucherId-- 3、脚本业务
-- 获取库存
local stock = redis.call('get', stockKey)
-- 判断库存是否存在或是否为空
if (stock == nil or stock == '') then-- 库存不存在或为空,返回错误码(例如 3 表示库存未初始化)return 1
end
-- 将库存转换为数字
local stockNum = tonumber(stock)
-- 判断库存是否为有效数字
if (stockNum == nil) then-- 库存不是有效数字,返回错误码(例如 4 表示库存数据异常)return 1
end
-- 判断库存充足与否
if (stockNum <= 0) then-- 库存不足return 1
end
-- 判断用户是否下单
if (redis.call('sismember', orderKey, userId) == 1) then-- 重复下单return 2
end
-- 扣库存 保存用户
redis.call('incrby', stockKey, -1)
redis.call('sadd', orderKey, userId)
-- 发送消息到队列中
redis.call('xadd', 'stream.orders', '*', 'userId', userId, 'voucherId', voucherId, 'id', orderId)
return 0
public Result seckillVoucher(Long voucherId) {//获取用户 线程Long userId = UserHolder.getUser().getId();//执行LUA脚本Long result = stringRedisTemplate.execute(SECKILL_SCRIPY,Collections.emptyList(),voucherId.toString(), userId.toString());int r = result.intValue();//判断结果是不是0if (r != 0) {//不是0 代表没有购买资格return Result.fail(r == 1 ? "库存不足" : "不能重复下单");}//是0 有购买资格,保存下单消息到阻塞队列中// TODO 保存阻塞队列VoucherOrder voucherOrder = new VoucherOrder();// 订单idlong orderId = redisIdWorker.nextId("order");voucherOrder.setId(orderId);// 用户idvoucherOrder.setUserId(userId);// 代金券idvoucherOrder.setVoucherId(voucherId);//创建阻塞队列orderTasks.add(voucherOrder);//获取代理对象 放入队列proxy = (IVoucherOrderService) AopContext.currentProxy();//返回订单idreturn Result.ok(orderId);}*

优化:基于阻塞队列实现秒杀优化

//异步处理线程池
private static final ExecutorService SECKILL_ORDER_EXECUTOR = Executors.newSingleThreadExecutor();
//在类初始化之后执行,因为当这个类初始化好了之后,随时都是有可能要执行的
@PostConstruct
private void init() {SECKILL_ORDER_EXECUTOR.submit(new VoucherOrderHandler());
}
// 用于线程池处理的任务
// 当初始化完毕后,就会去从对列中去拿信息private class VoucherOrderHandler implements Runnable{@Overridepublic void run() {while (true){try {// 1.获取队列中的订单信息VoucherOrder voucherOrder = orderTasks.take();// 2.创建订单handleVoucherOrder(voucherOrder);} catch (Exception e) {log.error("处理订单异常", e);}}}private void handleVoucherOrder(VoucherOrder voucherOrder) {//1.获取用户Long userId = voucherOrder.getUserId();// 2.创建锁对象RLock redisLock = redissonClient.getLock("lock:order:" + userId);// 3.尝试获取锁boolean isLock = redisLock.lock();// 4.判断是否获得锁成功if (!isLock) {// 获取锁失败,直接返回失败或者重试log.error("不允许重复下单!");return;}try {//注意:由于是spring的事务是放在threadLocal中,此时的是多线程,事务会失效proxy.createVoucherOrder(voucherOrder);} finally {// 释放锁redisLock.unlock();}}//aprivate BlockingQueue<VoucherOrder> orderTasks =new  ArrayBlockingQueue<>(1024 * 1024);@Overridepublic Result seckillVoucher(Long voucherId) {Long userId = UserHolder.getUser().getId();long orderId = redisIdWorker.nextId("order");// 1.执行lua脚本Long result = stringRedisTemplate.execute(SECKILL_SCRIPT,Collections.emptyList(),voucherId.toString(), userId.toString(), String.valueOf(orderId));int r = result.intValue();// 2.判断结果是否为0if (r != 0) {// 2.1.不为0 ,代表没有购买资格return Result.fail(r == 1 ? "库存不足" : "不能重复下单");}VoucherOrder voucherOrder = new VoucherOrder();// 2.3.订单idlong orderId = redisIdWorker.nextId("order");voucherOrder.setId(orderId);// 2.4.用户idvoucherOrder.setUserId(userId);// 2.5.代金券idvoucherOrder.setVoucherId(voucherId);// 2.6.放入阻塞队列orderTasks.add(voucherOrder);//3.获取代理对象proxy = (IVoucherOrderService)AopContext.currentProxy();//4.返回订单idreturn Result.ok(orderId);}@Transactionalpublic  void createVoucherOrder(VoucherOrder voucherOrder) {Long userId = voucherOrder.getUserId();// 5.1.查询订单int count = query().eq("user_id", userId).eq("voucher_id", voucherOrder.getVoucherId()).count();// 5.2.判断是否存在if (count > 0) {// 用户已经购买过了log.error("用户已经购买过了");return ;}// 6.扣减库存boolean success = seckillVoucherService.update().setSql("stock = stock - 1") // set stock = stock - 1.eq("voucher_id", voucherOrder.getVoucherId()).gt("stock", 0) // where id = ? and stock > 0.update();if (!success) {// 扣减失败log.error("库存不足");return ;}save(voucherOrder);}

代码逻辑及实现

1、使用 Executors.newSingleThreadExecutor() 创建一个单线程的线程池,用于异步处理订单

2、执行lua 判断是不是满足要求 满足要求 提交到线程池中 
         proxy = (IVoucherOrderService)AopContext.currentProxy();获取代理 存储到成员变量中,以便后续在异步线程中使用。

3、返回给用户已经完成

4、之后的就是在线程池中完成
        int count = query().eq("user_id", userId).eq("voucher_id", voucherOrder.getVoucherId()).count(); 这里做数据库二次检查,确保数据一致性(Redis 和数据库可能不同步) 

总结思路

  • 先利用Redis完成库存余量、一人一单判断,完成抢单业务

  • 再将下单业务放入阻塞队列,利用独立线程异步下单

http://www.cadmedia.cn/news/12310.html

相关文章:

  • 成都高薪南网站建设seo技术网网
  • 个人网站设计背景图谷歌seo课程
  • 重庆知名商城网站建设公司沧州网站seo
  • 青秀区网站建设论文收录网站排名
  • 中山建设企业网站网站seo培训
  • 版式网站有哪些千锋教育培训机构可靠吗
  • 多城市分站站群cms郑州百度seo
  • 做好系部宣传和网站建设营销渠道模式有哪些
  • 做网站投诉要钱吗互联网产品运营推广方案
  • 网站建设是百度舆情监测平台
  • 衡阳北京网站建设爱站在线关键词挖掘
  • 网站设计开发收费标准推广普通话手抄报内容简短
  • 怎么呢搜到自己建设的网站东莞推广系统
  • 360客户如何做网站推广站长之家seo工具包
  • 德清网站公司建设外链官网
  • pc端网页最好的关键词排名优化软件
  • 静态网站生成器怎样做新媒体运营培训课程
  • 360免费建站方法网络营销的工具和方法有哪些
  • 网站seo优化运营个人博客搭建
  • 网站 动态广州网页推广公司
  • 做海报找背景图有哪些网站厦门人才网app
  • 营销网站建立今天军事新闻最新消息
  • 网站做301重定向的作用个人博客网站搭建
  • 做时间轴的在线网站湖南网络推广公司大全
  • 网站开发与经营哈尔滨新闻头条今日新闻
  • 网站推广策划的思路包括哪些杭州排名推广
  • 建设政府网站合同杭州百度优化
  • 电影网站网页设计实训报告培训机构网站设计
  • 新闻网站建设毕业设计宁波专业seo外包
  • 建设工程月评打分网站bt樱桃 磁力岛