Redis实战学习(二)

任务:

  • 使用事务来解决一个竞争问题

现在介绍一下事务:Redis将一些列命令序列化,然后按照顺序执行,在一个事务执行的过程中,停止执行其他Redis客户端的请求,使得一个事务体现出和一个命令一样的原子性。

下面这段代码是没有用到事务的:

ONE_WEEK_IN_SECONDS = 7 * 86400
VOTE_SCORE = 432
def article_vote(conn, user, artivle):
    cutoff = time.time() - ONE_WEEK_SECONDS  
    if conn.zsocre('time:', article) < cutoff:
        return
    article_id = article.partition(':')[-1]
    if conn.sadd('voted:' + article_id, user):
        conn.zincrby('sorce:', article, VOTE_SCORE)
        conn.hincrby(article, 'votes', 1)
        
复制代码

下面这一段是使用事务:

ONE_WEEK_IN_SECONDS = 7 * 86400
VOTE_SCORE = 432
def new_article_vote(conn, user, article):
    cutoff = time.time() - ONE_WEEK_SECONDS  
    if conn.zsocre('time:', article) < cutoff:
        return
    article_id = article.partition(':')[-1]
    pipeline = conn.pipline()
    pipeline.sadd('voted:' + article_id, user);
    pipeline.zincrby('sorce:', article, VOTE_SCORE)
    pipeline.hincrby(article, 'votes', 1)
    pipeline.execute()
复制代码

  • 游戏玩家出售背包中的道具,将道具放到商场上

接下来实现一个能够记录游戏用户信息记录和用户背包内道具的例子使用到的知识点有事务,wacth,unwacth等:

def list_item(conn, itemid, sellerid, price):
    inventory = "inventory:%s" % sellerid
    item = "%s:%s" % (itemid, sellerid)
    end = time.time() + 5;
    pipe = conn.pipeline() // 流水线
    
    while time.time() < end:
        try:
            pipe.watch(inventory) // 监视用户背包,防止在事务执行前被修改
            if not pipe.sismember(inventory. itemid):  // 检查用户是否有将要被出售的道具
                pipe.unwatch() // 取消监视
                return None
            
            pipe.multi()  // 开启一个事务
            pipe.zadd('market:', item, price) // 将商品放入有序集合中(商场)
            pipe.srem(inventory, itemid) // 移除用户背包中的要出售道具
            pipe.execute() // // 事务执行,流水线发送给redis服务器
            return True
        expect redis.exceptions.WatchError:  // 用户背包发生了变化,就回抛出异常
            pass
复制代码
  • 游戏用户购买商品
def purchase_item(conn, buyerid, itemid, sellerid, lprice):
    buyer = "users:%s" % buyerid
    seller = "users:%s" % sellerid
    item = "%s:%s"%(itemid, sellerid)
    inventory = "inventory:%s" % buterid
    end = tiem.time()
    pipe = conn.pipeline()
    while time.time() < end
        try:
            pipe.watch("makert:", buyer); // 对商品买卖市场和买家进行监视
            price = int(pipe.zscore('market:', item) // 获取商场有序集合中item的分数,也就是价格
            funds = int(pipe.hget(buyers, "funds")) // 获取游戏玩家拥有的货币数
            if funds != lprice or price > funds:
                pipe.unwatch()
                return None
            
            pipe.multi()
            pipe.hincrby(seller, 'funds', price)  // 给卖家加卖掉道具的钱
            pipe.hincrby(buyer, 'funds', -price) // 买家扣除买道具的钱
            pipe.sadd(inventory, itemid)  // 将买来的道具加入买家背包(注意只是存入道具id)
            pipe.zrem('market:', item) // 移除商场上的道具记录
            pipe.execute() // 事务执行,流水线发送给redis服务器
            return True
        except redis.exceptions.WatchError:  //如果买家的个人信息和商场在事务执行中发生变化,就抛出和这个异常
            pass
    return fasle
复制代码

最后将明确几个概念,事务和非事务流水线

事务可以将一系列命令保存其中,一个事务执行过程中不会受到其他客户端的影响。 非事务流水线是将一系列命里,一次性发给Redis服务器,能够减少客户端和Redis服务器的交互,缺点会受到其他客户端的影响,但是效率比事务高。

ps:本人打字慢,写这个是真的费时间。

转载于:https://juejin.im/post/5b8e46f6e51d4538d42af3e4

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值