示例代码是基于博客 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实现的抢购代码示例的更多相关文章

  1. 基于jQuery表格增加删除代码示例

    <!doctype html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  2. 一种基于Redis的10行代码实现IP频率控制方法

    优点:可支持海量访问的频率控制,只需要增加Redis机器,单个Redis节点(只占用一个cpu core)即可支持10万/s以上的处理. 基于IP频率限制是种常见需求,基于Redis可以十分简单实现对 ...

  3. [IE编程] 多页面基于IE内核浏览器的代码示例

    有不少人发信问这个问题,我把答案贴在这里: 建议参考 WTL (Windows Template Library) 的代码示例工程TabBrowser  (在WTL目录/Samples/TabBrow ...

  4. 阿里云PHP Redis代码示例

    测试代码示例 <?php /* 这里替换为连接的实例host和port */ $host = "localhost"; $port = 6379; /* 这里替换为实例id和 ...

  5. [转载]基于Redis的Bloomfilter去重(附Python代码)

    前言: “去重”是日常工作中会经常用到的一项技能,在爬虫领域更是常用,并且规模一般都比较大.去重需要考虑两个点:去重的数据量.去重速度.为了保持较快的去重速度,一般选择在内存中进行去重. 数据量不大时 ...

  6. socket模块实现基于UDP聊天模拟程序;socketserver模块实现服务端 socket客户端代码示例

    socket模块 serSocket.setblocking(False) 设置为非阻塞: #coding=utf-8 from socket import * import time # 用来存储所 ...

  7. Redis学习手册(实例代码)

    在之前的博客中已经非常详细的介绍了Redis的各种操作命令.运行机制和服务器初始化参数配置.本篇博客是该系列博客中的最后一篇,在这里将给出基于Redis客户端组件访问并操作Redis服务器的代码示例. ...

  8. 分布式锁与实现(一)——基于Redis实现 【比较靠谱】

    转: 分布式锁与实现(一)——基于Redis实现 概述 目前几乎很多大型网站及应用都是分布式部署的,分布式场景中的数据一致性问题一直是一个比较重要的话题.分布式的CAP理论告诉我们“任何一个分布式系统 ...

  9. RedLock.Net - 基于Redis分布式锁的开源实现

    工作中,经常会遇到分布式环境中资源访问冲突问题,比如商城的库存数量处理,或者某个事件的原子性操作,都需要确保某个时间段内只有一个线程在访问或处理资源. 因此现在网上也有很多的分布式锁的解决方案,有数据 ...

随机推荐

  1. Java与c#的一些细节区别

    实习中用的语言是c#,第一次接触到这种语言,然后写的过程中,发觉和Java几乎一摸一样,好像根本是无缝切换,但细节仍有很大的区别,称有空总结一波里面的部分细节实现. ps. 我写c#过程中,发觉c#有 ...

  2. 修改git分支名称

    场景:将分支名称为 oldbranch 改为 newbranch 步骤: 1.将本地分支oldbranch切一个分支到本地 git branch -m oldbranch newbranch 2.删除 ...

  3. 修改mysql忽略大小写

    mysql -p --1.登录mysql show variables like "%case%";+------------------------+-------+| Vari ...

  4. Windows安装diango框架<一>

    下一篇:使用Django创建网站项目<二> python工具安装 python下载:https://www.python.org/downloads/windows/(我的版本3.7.0) ...

  5. 搜藏一个php文件上传类

    <?php /** * 上传文件类 * @param _path : 服务器文件存放路径 * @param _allowType : 允许上传的文件类型和所对应的MIME * @param _f ...

  6. Ajax提交用FormData()上传文件

    1.form声明如下 2.ajax设置如下 var formData = new FormData(document.getElementById("form")); $.ajax ...

  7. 详解promise、async和await的执行顺序

    1.题目和答案 一道题题目:下面这段promise.async和await代码,请问控制台打印的顺序? async function async1(){ console.log('async1 sta ...

  8. Js调试中不得不知的Console

    在js调试中,大部分的前端人员都是采用console.log()方法来打印出调试的数据,但是很多人都不知道console这个对象有很多很实在的方法,本文就来介绍一下这些方法的使用. 一.console ...

  9. Jmeter进阶篇之监控服务器cpu,内存

    对于Jmeter,可以不再赘述,因为介绍得也够多了. 那么相信有部分同学已经尝试着自主去学习如果使用Jmeter对服务器进行压力测试了. 但是可能也会发现,Jmeter好像监控不了服务器的cpu已经内 ...

  10. JMeter JMeter自身运行性能优化

    JMeter自身运行性能优化   by:授客 QQ:1033553122 测试环境 apache-jmeter-2.13   1.   问题描述 单台机器的下JMeter启动较大线程数时可能会出现运行 ...