基于Redis实现的抢购代码示例
示例代码是基于博客 https://blog.csdn.net/qq1013598664/article/details/70183908的错误案例修改而来,如果有问题望多多指点,错误代码可以去原文查阅,本文将会指出错误之处。
不多废话,直接上代码:
package com.javartisan.concurrent; import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.List;
import java.util.UUID; import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.Transaction; /**
* redis并发抢购测试
*
* @author javartisan
*/
public class RedisTest {
public static void main(String[] args) {
final String watchkeys = "watchkeys";
ExecutorService executor = Executors.newFixedThreadPool(20); GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig(); JedisPool jedisPool = new JedisPool(poolConfig, "127.0.0.1", 6379, 10000, "root"); final Jedis jedis = jedisPool.getResource();
jedis.auth("root");
jedis.set(watchkeys, "0");// 重置watchkeys为0
jedis.del("setsucc", "setfail");// 清空抢成功的,与没有成功的
jedis.close(); for (int i = 0; i < 10000; i++) {// 测试一万人同时访问
executor.execute(new MyRunnable(jedisPool));
}
executor.shutdown();
}
} class MyRunnable implements Runnable { String watchkeys = "watchkeys";// 监视keys
JedisPool jedisPool = null; public MyRunnable(JedisPool jedisPool) {
this.jedisPool = jedisPool;
} @Override
public void run() {
Jedis jedis = jedisPool.getResource(); try { jedis.watch(watchkeys);//代码块1 watchkeys String val = jedis.get(watchkeys);
int valint = Integer.valueOf(val);
String userifo = UUID.randomUUID().toString();
if (valint < 10) { Transaction tx = jedis.multi();//代码块2 开启事务
tx.incr("watchkeys");
List<Object> list = tx.exec();//代码块3 提交事务,如果此时watchkeys被改动了,则返回emptyList if (list.size() > 0) {
System.out.println("用户:" + userifo + "抢购成功,当前抢购成功人数:" + (valint + 1));
/* 抢购成功业务逻辑 */
jedis.sadd("setsucc", userifo);
return;
}
}
System.out.println("用户:" + userifo + "抢购失败");
jedis.sadd("setfail", userifo);
return; } catch (Exception e) {
e.printStackTrace();
} finally {
jedis.close();
} } }
原文错误之处在于对exec方法的处理,当事务被打断或者执行失败的话返回的是一个emptyList,并不是一个null,因此需要使用list.size判断事务状态。
Jedis中的exec方法实现源码:
public List<Object> exec() {
client.exec();
client.getAll(1); // Discard all but the last reply
inTransaction = false; List<Object> unformatted = client.getObjectMultiBulkReply();
if (unformatted == null) { //事务失败
return Collections.emptyList();
}
List<Object> formatted = new ArrayList<Object>();
for (Object o : unformatted) {
try {
formatted.add(generateResponse(o).get());
} catch (JedisDataException e) {
formatted.add(e);
}
}
return formatted;
}
Redis抢购成功数据:
抢购失败用户个数:
备注说明:
代码块1表示监督key,以准备执行事务,如果在事务执行期间该key对应的value被修改的话事务进行回滚。
代码块2到代码块3之间是开启事务执行命令并提交事务,在这个代码期间必须使用事务对象执行命令,否者会报错。即使用tx操作。
在事务中判断元素是否存在时候,返回的是一个Response对象,例如方法get:
redis.clients.jedis.RedisPipeline#get
public Response<String> get(String key) {
getClient(key).get(key);
return getResponse(BuilderFactory.STRING);
}
只能在事务执行完毕或者事务discard之后才可以get,不能再事务期间进行get。
秒杀系统结合限流系统一起处理效果会更好
基于Redis实现的抢购代码示例的更多相关文章
- 基于jQuery表格增加删除代码示例
<!doctype html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- 一种基于Redis的10行代码实现IP频率控制方法
优点:可支持海量访问的频率控制,只需要增加Redis机器,单个Redis节点(只占用一个cpu core)即可支持10万/s以上的处理. 基于IP频率限制是种常见需求,基于Redis可以十分简单实现对 ...
- [IE编程] 多页面基于IE内核浏览器的代码示例
有不少人发信问这个问题,我把答案贴在这里: 建议参考 WTL (Windows Template Library) 的代码示例工程TabBrowser (在WTL目录/Samples/TabBrow ...
- 阿里云PHP Redis代码示例
测试代码示例 <?php /* 这里替换为连接的实例host和port */ $host = "localhost"; $port = 6379; /* 这里替换为实例id和 ...
- [转载]基于Redis的Bloomfilter去重(附Python代码)
前言: “去重”是日常工作中会经常用到的一项技能,在爬虫领域更是常用,并且规模一般都比较大.去重需要考虑两个点:去重的数据量.去重速度.为了保持较快的去重速度,一般选择在内存中进行去重. 数据量不大时 ...
- socket模块实现基于UDP聊天模拟程序;socketserver模块实现服务端 socket客户端代码示例
socket模块 serSocket.setblocking(False) 设置为非阻塞: #coding=utf-8 from socket import * import time # 用来存储所 ...
- Redis学习手册(实例代码)
在之前的博客中已经非常详细的介绍了Redis的各种操作命令.运行机制和服务器初始化参数配置.本篇博客是该系列博客中的最后一篇,在这里将给出基于Redis客户端组件访问并操作Redis服务器的代码示例. ...
- 分布式锁与实现(一)——基于Redis实现 【比较靠谱】
转: 分布式锁与实现(一)——基于Redis实现 概述 目前几乎很多大型网站及应用都是分布式部署的,分布式场景中的数据一致性问题一直是一个比较重要的话题.分布式的CAP理论告诉我们“任何一个分布式系统 ...
- RedLock.Net - 基于Redis分布式锁的开源实现
工作中,经常会遇到分布式环境中资源访问冲突问题,比如商城的库存数量处理,或者某个事件的原子性操作,都需要确保某个时间段内只有一个线程在访问或处理资源. 因此现在网上也有很多的分布式锁的解决方案,有数据 ...
随机推荐
- 【Java基础】10、Java中throw和throws的区别
系统自动抛出的异常 所有系统定义的编译和运行异常都可以由系统自动抛出,称为标准异常,并且 Java 强烈地要求应用程序进行完整的异常处理,给用户友好的提示,或者修正后使程序继续执行. 语句抛出的异常 ...
- JavaScript一团乱,这是好事
译者按: JavaScript从简单变复杂了,作者从另一个角度看待这个问题. 原文: JavaScript’s a mess – and that’s a good thing 译者: Fundebu ...
- Python 练习:三级菜单选择城市
info = { 'GuangDong':{ 'GuangZhou': ['TianHe', 'HaiZhu'], 'MaoMing': ['MaoNan', 'DianBai']}, 'ShanDo ...
- 关于wsgi协议的理解
基础概念 首先要了解 WSGI 规范的概念,WSGI(Web Server Gateway Interface)规范描述了web server(Gunicorn,uWSGI等)如何与web appli ...
- json&pickle数据序列化模块
用于序列化的模块 json,通用的序列化方式,序列化成为str类型,支持所有语言识别,序列化的数据具有局限性. pickle,python的所有数据类型都可以被序列化,序列化为bites格式,只适用于 ...
- 【读书笔记】iOS-基带攻击
一,iOS设备中的蜂窝网络通信栈运行在专门的芯片上,这个芯片就是数字基带处理器. 参考资料:<黑客攻防技术宝典-iOS实战篇>
- Salesforce的Developer Console简介
Developer Console是Salesforce提供的一个基于浏览器的集成开发环境.在Developer Console中,开发者可以新建.修改各种Apex.Visualforce.Light ...
- How to deploy kotlin in androidstudio?
Kotlin is a good language,more playable than Java.So how do we deploy kotlin? First,install the kotl ...
- tinypng upload一键压缩上传工具,告别人肉
地址 项目地址:tinypng-upload 有兴趣的可以玩一玩,因为平时经常会用到图片压缩,上传,如果你也觉得很繁琐的话,这个将会解决你的痛点. 关于 tinypng-upload 这是一个基于 e ...
- 动态导入模块:__import__、importlib、动态导入的使用场景
相关内容: __import__ importlib 动态导入的使用场景 首发时间:2018-02-23 16:06 __import__: 功能: 是一个函数,可以在需要的时候动态导入模块 使用: ...