Redis学习 Redis+Lua抢红包实战(五)

抢红包实战预热

List队列:将N个红包放到List队列中,用来初始化红包池子

执行命令,如何将多个红包放到放到hongBaoPool中

lpush  hongBaoPoolKey  {id:rid_1, money:9}

lpush  hongBaoPoolKey  {id:rid_2, money:8}

lpush  hongBaoPoolKey  {id:rid_3, money:12}

lpush  hongBaoPoolKey  {id:rid_N, money:15}

抢红包实战用到的基础命令

List类型:记录用户抢了多少钱

 

执行命令,如何将多个红包放到放到hongBaoDetailListKey 中

lpush  hongBaoDetailListKey {id:rid_N, money:15,userId:N}

lpush  hongBaoDetailListKey {id:rid_8, money:15,userId:3}

lpush  hongBaoDetailListKey {id:rid_3, money:15,userId:2}

lpush  hongBaoDetailListKey {id:rid_1, money:15,userId:1}

Hash类型:记录哪些用户已抢过红包,防止重复抢

执行命令,如何将多个红包放到放到hongBaoPool中

hset  userIdRecordKey 001 1

hset  userIdRecordKey 002 1

hset  userIdRecordKey 003 1

hset  userIdRecordKey 00N 1

业务流程

1,先初始化红包池:

lpush  hongBaoPool  {id:rid_1, money:9}  //将N个红包信息放入hongBaoPool 中

2,Lua实现抢红包流程:

代码实现:

常量类:

public class Basic {
	public static String ip = "192.168.46.133";
	public static int port = 6379;
	public static String auth = "12345678";
	public static int honBaoCount = 1000;

	public static int threadCount = 20;
	public static String hongBaoPoolKey = "hongBaoPoolKey"; //LIST类型来模拟红包池子
	public static String hongBaoDetailListKey = "hongBaoDetailListKey";//LIST类型,记录所有用户抢红包的详情
	public static String userIdRecordKey = "userIdRecordKey";//记录已经抢过红包的用户ID,防止重复抢
	
	/*
	 * KEYS[1]:hongBaoPool:                   //键hongBaoPool为List类型,模拟红包池子,用来从红包池抢红包
	 * KEYS[2]:hongBaoDetailList://键hongBaoDetailList为List类型,记录所有用户抢红包的详情
	 * KEYS[3]:userIdRecord :           //键userIdRecord为Hash类型,记录所有已经抢过红包的用户ID
	 * KEYS[4]:userid :                              //模拟抢红包的用户ID
	 * 
	 * 
	 * jedis.eval(  Basic.getHongBaoScript,   4,    Basic.hongBaoPoolKey,  Basic.hongBaoDetailListKey,	Basic.userIdRecordKey,  userid);
	 *                      Lua脚本                                参数个数                  key[1]                     key[2]                       key[3]      key[4]                   
	*/
	public static String getHongBaoScript =   
				     //查询用户是否已抢过红包,如果用户已抢过红包,则直接返回nil 
		            "if redis.call('hexists', KEYS[3], KEYS[4]) ~= 0 then\n"   + 
		                 "return nil\n" + 
		            "else\n"  +
		                  //从红包池取出一个小红包
		                  "local hongBao = redis.call('rpop', KEYS[1]);\n"  +
		                  //判断红包池的红包是否为不空
		            	  "if hongBao then\n"  +
			            	 "local x = cjson.decode(hongBao);\n"  +
		            	     //将红包信息与用户ID信息绑定,表示该用户已抢到红包 
			            	 "x['userId'] = KEYS[4];\n"  +
			            	 "local re = cjson.encode(x);\n"  +
			            	  //记录用户已抢过userIdRecordKey  hset userIdRecordKey  userid 1
			            	 "redis.call('hset', KEYS[3], KEYS[4], '1');\n"  +
			            	  //将抢红包的结果详情存入hongBaoDetailListKey
			            	 "redis.call('lpush', KEYS[2], re);\n" + 
			            	 "return re;\n"  +
		                  "end\n"  +
		            "end\n"  +
		            "return nil";  
}

生成红包类:

public class GenRedPack {
	/**
	 * 多线程模拟红包池初始化  Jedis类
	 */
	public static void genHongBao() throws InterruptedException {
		final JedisUtils jedis = new JedisUtils(Basic.ip, Basic.port, Basic.auth);
		jedis.flushall();  //清空,线上不要用.....

		//发枪器
		final CountDownLatch latch = new CountDownLatch(Basic.threadCount);
		
		for(int i = 0 ; i < Basic.threadCount; i++){
			final int page = i;
			Thread thread = new Thread(){
				public void run(){
					//每个线程要初始化多少个红包
					int per = Basic.honBaoCount/Basic.threadCount;
					
					JSONObject object = new JSONObject();
					
					for(int j = page * per ; j < (page+1) * per; j++){ //从0开始,直到
						object.put("id", "rid_"+j); //红包ID
						object.put("money", j);   //红包金额
						//lpush key value===lpush hongBaoPoolKey {id:rid_1, money:23}
						jedis.lpush("hongBaoPoolKey", object.toJSONString());
					}
					latch.countDown(); //发枪器递减
				}
			};
			thread.start();
		}
		latch.await();//所有线程处于等状态
	}
}

抢红包类:

/**
 * 多线程模拟用户抢红包
 */
public class GetRedPack {
    //抢红包的方法
	static public void getHongBao() throws InterruptedException {
		final CountDownLatch latch = new CountDownLatch(Basic.threadCount);//20 //发枪器
		for(int i = 0 ; i < Basic.threadCount ; i ++){  //20线程
			Thread thread = new Thread(){
				public void run(){
					//拿到jedis连接
					JedisUtils jedis = new JedisUtils(Basic.ip, Basic.port, Basic.auth);
					while(true){
						
						
						//模拟一个用户ID使用UUID XXXX
						String userid = UUID.randomUUID().toString();
						
						
						//抢红包  eval 可以直接调用我们LUA脚本里的业务代码  object ={rid_1:1, money:9, userid:001}
						Object object = jedis.eval(Basic.getHongBaoScript,4,Basic.hongBaoPoolKey,Basic.hongBaoDetailListKey,Basic.userIdRecordKey,userid);
						
						
						if(null != object){
							System.out.println("用户ID号:"+userid+" 抢到红包的详情是 "+object);
						}else{
							if(jedis.llen(Basic.hongBaoPoolKey) == 0){
								break;
							}
						}
					}
					latch.countDown();
				}
		};
		thread.start();

		}
		latch.await();
	}
}

main:

public class MainTestRedPack {
	

	public static void main(String[] args) throws InterruptedException {
		GenRedPack.genHongBao();//初始化红包
		
		GetRedPack.getHongBao();//从红包池抢红包
	
	}
}

 

Lua实现核心业务-什么是Lua语言

Lua  是一个小巧的脚本语言,由标准C编写而成,代码简洁优美,几乎在所有操作系统和平台上都可以编译,运行。 一个完整的Lua解释器不过200k,在目前所有脚本引擎中,Lua的速度是最快的。 Lua语言里的操作提供原子性。

Lua实现核心业务

Object object = jedis.eval(getHongBaoScript,     4,         hongBaoPoolKey,    hongBaoDetailListKey,  userIdRecordKey,    userid );

 

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值