示例代码是基于博客 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. DDD初探

    领域驱动设计(DDD)对开发者来说是面向对象设计的自然进化 总的来说DDD包括两个部分: 分析部分 分析部分通常是由开发人员去和领域专家沟通业务知识,但是开发人员和领域专家是有代沟的, 为了简化沟通成 ...

  2. c# 判断是否是手机访问

    public static bool CheckAgent() { bool flag = false; string agent = HttpContext.Current.Request.User ...

  3. Transformation和Action

    spark的运算操作有两种类型:分别是Transformation和Action,区别如下:   Transformation:代表的是转化操作就是我们的计算流程,返回是RDD[T],可以是一个链式的 ...

  4. 【Java深入研究】1、object类

    一.概述Object类是所有Java类的祖先.每个类都使用 Object 作为超类.所有对象(包括数组)都实现这个类的方法. 参考英文:* Class {@code Object} is the ro ...

  5. python全局解释器锁(GIL)

    文章作者:卢钧轶(cenalulu) 本文原文地址:http://cenalulu.github.io/python/gil-in-python/ ,对文章做了适当的修改,加入了一些自己的理解. CP ...

  6. session一致性架构设计

    什么是session? 由于HTTP协议是无状态的协议,因此它不会去记住上一次浏览器访问服务器时的信息.同一个用户的两次操作,与两个不同用户的操作,对它来说是一样的. 这样虽然满足了互联网web应用的 ...

  7. HDU1559

    最大子矩阵 Time Limit: 30000/10000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Sub ...

  8. linux下怎么进入本机mysql

    sudo /etc/init.d/mysql startmysql -u xxxx -p*****mysql >_

  9. 初学HTML-10

    marquee标签:设置文字滚动效果. 格式:<marquee>文字滚动</marquee> 属性:direction:设置滚动方向:left / right / up / d ...

  10. 消息队列&Celery&RabbitMQ&zeromq

    一.消息队列 什么是消息队列? “消息队列”是在消息的传输过程中保存消息的容器. “消息”是在两台计算机间传送的数据单位.消息可以非常简单,例如只包含文本字符串:也可以更复杂,可能包含嵌入对象. 消息 ...