Redis两种秒杀抢购思路
方式一:使用DECR减库存
/** * 外卡进入减库存 * @param competitionQuarterInDTO * @return */@Overridepublic int otherCardEnter(CompetitionQuarterInDTO competitionQuarterInDTO) throws IOL8ServiceException, IOL8CommonException { if(NumberUtils.isNumberNull(competitionQuarterInDTO.getCompetitionQuarter()) || StringUtils.isBlank(competitionQuarterInDTO.getTranslatorId())){ throw IOL8ServiceExceptionBuilder.exceptionBuilder().createException(ErrorCode.ERROR_CODE_240002); } Jedis jedis = null; try{ JedisPool pool = JedisUtils.getJedisPool(); jedis = pool.getResource(); Integer num = getPassStock(jedis, competitionQuarterInDTO.getCompetitionQuarter()); if(num > 0){ Integer isEnter = (Integer)redisTemplate.opsForHash().get(RedisConstants.TRANSLATOR_PREHEAT_PASS_STOCK, competitionQuarterInDTO.getTranslatorId()); if(isEnter == null){ redisTemplate.opsForHash().put(RedisConstants.TRANSLATOR_PREHEAT_PASS_STOCK, competitionQuarterInDTO.getTranslatorId(), 1); jedis.decrBy(RedisConstants.PREHEAT_PASS_STOCK, 1); } } else { throw IOL8ServiceExceptionBuilder.exceptionBuilder().createException(ErrorCode.ERROR_CODE_241001); } } finally { JedisUtils.closeResource(jedis); } return 1;} /** * 获取pass卡剩余库存 * @return */private Integer getPassStock(Jedis jedis, Long competitionQuarter){ String preheatPassStock = jedis.get(RedisConstants.PREHEAT_PASS_STOCK); Integer num = 0; //第一次获取外卡,取库存放入缓存 if(preheatPassStock == null || StringUtils.isBlank(preheatPassStock)){ CompetitionQuarter competitionQuarterResult = competitionQuarterMapper.selectByPrimaryKey(competitionQuarter); jedis.set(RedisConstants.PREHEAT_PASS_STOCK, competitionQuarterResult.getPassStock().toString()); num = competitionQuarterResult.getPassStock(); } else { num = Integer.valueOf(preheatPassStock); } return num;} 方式二:使用Redis Watch
1、使用watch,采用乐观锁
2、不使用悲观锁,因为等待时间非常长,响应慢
3、不使用队列,因为并发量会让队列内存瞬间升高
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;import redis.clients.jedis.Jedis;/*** redis测试抢购* * @author 10255_000 * */ public class RedisTest { public static void main(String[] args) { final String watchkeys = "watchkeys"; ExecutorService executor = Executors.newFixedThreadPool(20); final Jedis jedis = new Jedis("192.168.3.202", 6379); jedis.set(watchkeys, "0");// 重置watchkeys为0 jedis.del("setsucc", "setfail");// 清空抢成功的,与没有成功的 jedis.close(); for (int i = 0; i < 10000; i++) {// 测试一万人同时访问 executor.execute(new MyRunnable()); } executor.shutdown(); } } import java.util.List; import java.util.UUID; import redis.clients.jedis.Jedis; import redis.clients.jedis.Transaction; public class MyRunnable implements Runnable { String watchkeys = "watchkeys";// 监视keys Jedis jedis = new Jedis("192.168.3.202", 6379); public MyRunnable() { } @Override public void run() { try { jedis.watch(watchkeys);// watchkeys String val = jedis.get(watchkeys); int valint = Integer.valueOf(val); String userifo = UUID.randomUUID().toString(); if (valint < 10) { Transaction tx = jedis.multi();// 开启事务 tx.incr("watchkeys"); List<Object> list = tx.exec();// 提交事务,如果此时watchkeys被改动了,则返回null if (list != null) { System.out.println("用户:" + userifo + "抢购成功,当前抢购成功人数:" + (valint + 1)); /* 抢购成功业务逻辑 */ jedis.sadd("setsucc", userifo); } else { System.out.println("用户:" + userifo + "抢购失败"); /* 抢购失败业务逻辑 */ jedis.sadd("setfail", userifo); } } else { System.out.println("用户:" + userifo + "抢购失败"); jedis.sadd("setfail", userifo); // Thread.sleep(500); return; } } catch (Exception e) { e.printStackTrace(); } finally { jedis.close(); } } }
Redis对事物的支持目前比较简单。Redis只能保证一个client发起的事务中的命令可以连续的执行,但后面命令出错前面不会回滚。而中间不会插入其他client的命令。当一个client在找一个连续中发出multi命令时,这个链接会进入一个事务上下文,该链接后续的命令不会立即执行,而是先放到队列中,当执行exec命令是,redis会顺序的执行队列中的所有命令。当如果队列中有命令错误,不会回滚。
乐观锁:大多数是基于数据版本(version)的记录机制实现的。即为数据增加一个版本标识,在基于数据库表的版本解决方案中,一般是通过为数据库表添加一个”version”字段来实现读取出数据时,将此版本号一同读出,之后更新时,对此版本号+1。此时,将提交数据的版本号与数据库表对应记录版本号进行比对,如果提交的数据版本号大于数据当前版本号,则予以更新,否则认为是过去数据。
在Redis中,使用watch命令实现乐观锁(watch key):
watch命令会监视给定的key,当exec时,如果监视的key从调用watch后发生过变化,则事务会失败,也可以调用wathc多长监视多个key。这样就可以对指定key加乐观锁了。注意watch的可以是对整个连接有效的。事务也一样。如果连接断开,监视和事务都会被自动清除。当然exec,discard,unwatch命令都会清除连接中的所有监视。
转载于:https://www.cnblogs.com/barrywxx/p/8563507.html
Redis两种秒杀抢购思路相关推荐
- redis使用watch秒杀抢购思路
1.使用watch,采用乐观锁 2.不使用悲观锁,因为等待时间非常长,响应慢 3.不使用队列,因为并发量会让队列内存瞬间升高 package com.javartisan.concurrent;i ...
- 前端图片有时候能显示有时候不显示_web前端基础教程:两种数据存储思路
Web前端开发基础,Web前端基础教程 数据存储是数据流在加工过程中产生的临时文件或加工过程中需要查找的信息.数据以某种格式记录在计算机内部或外部存储介质上.数据存储要命名,这种命名要反映信息特征的组 ...
- Redis两种持久化方式(RDBAOF)
爬虫和转载请注明原文地址;博客园蜗牛:http://www.cnblogs.com/tdws/p/5754706.html Redis的持久化过程中并不需要我们开发人员过多的参与,我们要做的是什么呢? ...
- 探究Redis两种持久化方式下的数据恢复
对长期奋战在一线的后端开发人员来说,都知道redis有两种持久化方式RDB和AOF,虽说大家都知道这两种方式大概运作方式,但想必有实操的人不会太多. 这里是自己实操两种持久化方式的一点点记录. 先看以 ...
- (三)Redis两种持久化方案
Redis的持久化策略:2种 RDB方式的持久化是通过快照(snapshotting)完成的,当符合一定条件时Redis会自动将内存中的数据进行快照并持久化到硬盘.RDB是Redis默认采用的持久化方 ...
- redis两种持久化模式
<meta charset="utf-8"> 一:快照模式 或莫过于SNAPSHOTTING模式,这个不需要反驳吧,而且你可能还知道,使用SNAPSHOTTING模式, ...
- Redis学习一:Redis两种持久化机制
申明 本文章首发自本人公众号:壹枝花算不算浪漫,如若转载请标明来源! 感兴趣的小伙伴可关注个人公众号:壹枝花算不算浪漫 22.jpg 前言 Redis是基于内存来实现的NO SQL数据库,但是我么你都 ...
- 来说说Redis两种持久化方式的优缺点
前言 Redis是一种K-V数据库,它的数据也可以进行持久化操作.因为redis的数据都保存在内存中,如果不进行及时的持久化,可能就会因为重启导致数据的丢失.这时候就需要对redis进行持久化操作,将 ...
- 快速排序两种最基本思路
基本思想 快速排序是对冒泡排序的一种改进 基本思想: 通过一趟排序将要排序的数据分割成独立的两部分. 其中一部分的所有数据都比另外一部分的所有数据都要小. 然后再按此方法对这两部分数据分别进行快速排序 ...
最新文章
- 《如何高效学习》作者推荐!
- 如何将重复的数据标红_python如何处理重复值数据?
- 线程并发与进程并发各有什么you_操作系统问答题总结
- cheerio获取元素内文本,但不包括其子元素内的文本值的方法
- 天正双击墙体不能编辑_天正CAD绘图必须要知道的技巧
- sql获取当前时间精确到秒的字符串
- 程序员如何写工作日志?
- 游戏开发中的沟通成本
- 上海大学2020计算机考研专业,2019上海大学计算机专业考研参考科目
- 面试题 - 浏览器兼容性问题与解决方案
- matlab二重定积分_matlab 对于变限积分的计算,二重积分 三重积分
- Tableau学习摘录总结①(层次、聚合度和颗粒度层次、聚合度和颗粒度,字段(离散和连续),小建议)
- 什么叫贴片(电子元器件)
- 一道对10年间中国行政区划个数进行对比的Python考试题
- python爬虫,wallhaven热门壁纸多线程采集下载源码
- 【docker专栏5】详解docker镜像管理命令
- /u200B 8203 Zero-width space 问题
- 汉字转拼音再转ASCII
- mysql数据库时间不准确_主数据库(mysql)的时间不对
- 正态分布/卡方分布/F分布/T分布