参考《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));
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。