参考《redis 实战》
需要
1、商品交易的主体是集体,集体领有姓名、资产属性。
2、每个人都有 N 个商品,每个商品都有惟一的商品编号。
3、容许商品投放到市场进行交易,一经投放,则商品从集体转移到市场,市场的商品依照价格排序。
4、交易须要判断资产是否足够,如果足够,商品从市场转移到买家
5、商品从集体到市场,或者市场到集体,都须要事务判断
剖析
第一个需要
能够用键值对保留姓名和资产信息,主键为用户的 id,hincrBy 办法对资产进行减少或缩小。以下是 hmset、hgetall、hincrBy 的用法。
// 赋值
local:0>hmset person:1 name zhangsan funds 100
"OK"
// 显示 hash 内容
local:0>hgetall person:1
1) "name"
2) "zhangsan"
3) "funds"
4) "100"
// 对 hash 的某个 key 的值进行相加
local:0>hincrBy person:1 funds 20
"120"
// 显示 hash 内容
local:0>hgetall person:1
1) "name"
2) "zhangsan"
3) "funds"
4) "120"
第二个需要
能够用汇合来存储商品,主键是商品的 id,汇合里放商品的编号。以下是 sadd、smembers、sismember、srem 的用法。
// 退出汇合
local:0>sadd package:1 itemX
"1"
local:0>sadd package:1 itemY
"1"
local:0>sadd package:1 itemZ
"1"
// 显示汇合元素
local:0>smembers package:1
1) "itemZ"
2) "itemX"
3) "itemY"
// 汇合是否存在某个元素,1 为是
local:0>sismember package:1 itemX
"1"
// 移除汇合的元素
local:0>srem package:1 itemX
"1"
// 汇合是否存在某个元素,0 为否
local:0>sismember package:1 itemX
"0"
// 显示汇合元素
local:0>smembers package:1
1) "itemZ"
2) "itemY"
第三个需要
市场的商品排序,须要按价格排序,所以能够用有序汇合。以下是 zadd、zrevrange、zrem 的用法。
// 新增元素
local:0>zadd market: 10 itemX.1
"1"
local:0>zadd market: 11 itemY.1
"1"
local:0>zadd market: 12 itemY.2
"1"
// 从高到低排序
local:0>zrevrange market: 0 -1 withscores
1) "itemY.2"
2) "12"
3) "itemY.1"
4) "11"
5) "itemX.1"
6) "10"
// 移除
local:0>zrem market: itemY.1
"1"
local:0>zrevrange market: 0 -1 withscores
1) "itemY.2"
2) "12"
3) "itemX.1"
4) "10"
第四个需要
从 hash 取出资产,跟商品金额进行判断
第五个需要
在 redis 中,事务的开始是以 MULTI 开始,EXEC 完结。在事务之间能够传输多个命令,然而实际上这些命令并不会被执行,直到调用 EXEC 的时候才会执行。
redis 还提供了 WATCH 和 UNWATCH 对 key 进行监控和勾销监控,如果事务执行之前,这些 key 被改变,则事务将会被中断。
UNWATCH 在 WATCH 之后以及 MULTI 前勾销对 key 的监控,DISCARD 在 MULTI 执行之后,EXEC 执行之前放弃执行事务块内的所有命令。
通过 watch 监听数据,而不是间接加锁,雷同于 CAS 的乐观锁和 synchronized 的乐观锁。
实际
定义用户
@Test
public void person() {Map<String, String> zhangsanMap = new HashMap();
zhangsanMap.put("name", "张三");
zhangsanMap.put("funds", "100");
JedisUtils.hmset("person:1", zhangsanMap);
Map<String, String> lisiMap = new HashMap();
lisiMap.put("name", "李四");
lisiMap.put("funds", "10");
JedisUtils.hmset("person:2", lisiMap);
System.out.println("张三的信息:" + JedisUtils.hgetAll("person:1"));
System.out.println("李四的信息:" + JedisUtils.hgetAll("person:2"));
}
定义用户的商品
@Test
public void personPackage() {
// 张三的商品
JedisUtils.sadd("package:1", "itemX");
JedisUtils.sadd("package:1", "itemY");
JedisUtils.sadd("package:1", "itemZ");
System.out.println("张三的商品:" + JedisUtils.smembers("package:1"));
// 李四的商品
JedisUtils.sadd("package:2", "itemA");
JedisUtils.sadd("package:2", "itemB");
JedisUtils.sadd("package:2", "itemC");
System.out.println("李四的商品:" + JedisUtils.smembers("package:2"));
}
商品投放市场
@Test
public void putMarket() {System.out.println("张三的商品:" + JedisUtils.smembers("package:1"));
System.out.println("市场的商品:" + JedisUtils.zrangeWithScores("market:", 0, -1));
while (true) {Jedis jedis = JedisUtils.watch("package:1");
// 曾经不存在了,则不监听
if (!JedisUtils.sismember("package:1", "itemX")) {jedis.unwatch();
break;
}
Transaction transaction = jedis.multi();
// 张三的商品移除
transaction.srem("package:1", "itemX");
// 市场的商品减少
transaction.zadd("market:", 8, "itemX.1");
List<Object> exec = transaction.exec();
// 不为空阐明执行胜利,跳出循环
if (null != exec) {break;}
}
System.out.println("张三的商品:" + JedisUtils.smembers("package:1"));
System.out.println("市场的商品:" + JedisUtils.zrangeWithScores("market:", 0, -1));
}
购买商品
@Test
public void getMarket() {System.out.println("张三的信息:" + JedisUtils.hgetAll("person:1"));
System.out.println("李四的信息:" + JedisUtils.hgetAll("person:2"));
System.out.println("李四的商品:" + JedisUtils.smembers("package:2"));
System.out.println("市场的商品:" + JedisUtils.zrangeWithScores("market:", 0, -1));
while (true) {
// 监听商品是否被其他人买走了
Jedis jedis = JedisUtils.watch("market:");
double price = JedisUtils.zscore("market:", "itemX.1");
double funds = Double.valueOf(JedisUtils.hmget("person:2", "funds").get(0));
if (price > funds) {jedis.unwatch();
break;
}
Transaction transaction = jedis.multi();
// 张三的金额新增
transaction.hincrBy("person:1", "funds", new Double(price).longValue());
// 李四的金额缩小
transaction.hincrBy("person:2", "funds", new Double(-price).longValue());
// 市场的商品移除
transaction.zrem("market:", "itemX.1");
// 李四的商品新增
transaction.sadd("package:2", "itemX");
List<Object> exec = transaction.exec();
// 不为空阐明执行胜利,跳出循环
if (null != exec) {break;}
}
System.out.println("张三的信息:" + JedisUtils.hgetAll("person:1"));
System.out.println("李四的信息:" + JedisUtils.hgetAll("person:2"));
System.out.println("李四的商品:" + JedisUtils.smembers("package:2"));
System.out.println("市场的商品:" + JedisUtils.zrangeWithScores("market:", 0, -1));
}