乐趣区

关于redis:redis-商品交易

参考《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));
}
退出移动版