redis - 商品交易

參考《redis實戰》redis

需求

一、商品交易的主體是我的,我的擁有姓名、資產屬性。
二、每一個人都有N個商品,每一個商品都有惟一的商品編號。
三、容許商品投放到市場進行交易,一經投放,則商品從我的轉移到市場,市場的商品按照價格排序。
四、交易須要判斷資產是否足夠,若是足夠,商品從市場轉移到買家
五、商品從我的到市場,或者市場到我的,都須要事務判斷

分析

第一個需求

能夠用鍵值對保存姓名和資產信息,主鍵爲用戶的id,hincrBy方法對資產進行增長或減小。如下是hmset、hgetall、hincrBy的用法。code

// 賦值
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取出資產,跟商品金額進行判斷rem

第五個需求

在redis中,事務的開始是以MULTI開始,EXEC結束。在事務之間能夠傳輸多個命令,可是實際上這些命令並不會被執行,直到調用EXEC的時候纔會執行。
redis還提供了WATCH和UNWATCH對key進行監控和取消監控,若是事務執行以前,這些key被改動,則事務將會被中斷。
UNWATCH在WATCH以後以及MULTI前取消對key的監控,DISCARD在MULTI執行以後,EXEC執行以前放棄執行事務塊內的全部命令。
經過watch監聽數據,而不是直接加鎖,雷同於CAS的樂觀鎖和synchronized的悲觀鎖。get

實踐

定義用戶

@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));
}
相關文章
相關標籤/搜索