zoukankan      html  css  js  c++  java
  • Redis实战

    介绍

    1. redis的目标的是: 简洁,高效,由于事务本身就是一个很复杂的东西,所有我们不能把事务做的太复杂。
    • DISCARD 取消事务,放弃执行事务块内的所有命令。

    • EXEC 执行所有事务块内的命令。

    • MULTI 标记一个事务块的开始。

    • UNWATCH 取消 WATCH 命令对所有 key 的监视。

    • WATCH key [key ...] 监视一个(或多个) key ,如果在事务执行之前这个(或这些) key 被其他命令所改动,那么事务将被打断。

      MULTI 和 EXEC

      127.0.0.1:6379> multi 
    OK
    127.0.0.1:6379> lpush fruits orange
    QUEUED
    127.0.0.1:6379> lpush fruits nut
    QUEUED
    127.0.0.1:6379> lpush fruits apple
    QUEUED
    127.0.0.1:6379> exec
    1) (integer) 1
    2) (integer) 2
    3) (integer) 3
    

    我们发现命令是一起执行的,如果说我的某一条命令执行失败,会回滚吗?
    答案是不会回滚。看看下面的原子性。

    原子性

    事务的原子性是指要么事务全部成功,要么全部失败,那么 Redis 事务执行是原子性的么? 下面我们来看一个特别的例子。

    > multi 
    OK 
    > set books iamastring      # 执行成功
    QUEUED 
    > incr books             # 执行失败
    QUEUED 
    > set poorman iamdesperate   # 执行成功
    QUEUED 
    > exec 
    1) OK 
    2) (error) ERR value is not an integer or out of range 
    3) OK 
    > get books 
    "iamastring" 
    >  get poorman 
    "iamdesperate 
    

      上面的例子是事务执行到中间遇到失败了,因为我们不能对一个字符串进行数学运算,事务在遇到指令执行失败后,后面的指令还继续执行,所以 poorman 的值能继续得到设置。
      到这里,你应该明白 Redis 的事务根本不能算「原子性」,而仅仅是满足了事务的「隔离性」,隔离性中的串行化——当前执行的事务有着不被其它事务打断的权利。

    Watch

    我在执行lpush的时候,lpush被其他人改变了。

    需求:在写multi的时候,不可以有其他的命令更改 “队列”中的集合。

    出现并发问题,因为有多个客户端会并发进行操作。我们可以通过 Redis 的分布式锁来避免冲突,这是一个很好的解决方案。分布式锁是一种悲观锁,那是不是可以使用乐观锁的方式来解决冲突呢?
    Redis 提供了这种 watch 的机制,它就是一种乐观锁。有了 watch 我们又多了一种可以用来解决并发修改的方法。 watch 的使用方式如下:

    127.0.0.1:6379> watch msg
    OK
    127.0.0.1:6379> multi
    OK
    127.0.0.1:6379> set msg "hello wolrd"
    QUEUED
    127.0.0.1:6379> exec
    (nil)
    127.0.0.1:6379> get msg
    "12345"
    127.0.0.1:6379> 
    

    注意事项
    Redis 禁止在 multi 和 exec 之间执行 watch 指令,而必须在 multi 之前做好盯住关键变量,否则会出错。

    .net操练,在StackExchange.Redis又该怎么做?

    更复杂的事实是StackExchange.Redis使用的是多路复用器的方式。

    我们不能只让并发调用方发布 WATCH / UNWATCH / MULTI / EXEC / DISCARD:这应该是混合在一起的。所以一个额外的抽象被给出:另外会让使事情更简单准确:约束。约束是预定义测试包括 WATCH 某种类型的测试并对结果进行检查。如果所有的约束都通过了,那么要么是以 MULTI / EXEC 发布(从事务开始,到执行整个事务块);要么是以 UNWATCH 发布(取消 WATCH 命令对所有 key 的监视)。阻止命令于其它调用方被混合在一起;所以例子可以是:

    注意:从 CreateTransaction 返回的对象最后都是调用异步方法来执行命令(Execute方法最终也是调用ExecuteAsync,具体可以看源码):由于不知道每个操作的结果,除非在 Execute 或 ExecuteAsync 操作完成后。如果操作没有被执行,所有的Task 将被标记为取消,否则在命令执行后你可以获取每个正常的结果。

           static void Transaction()
            {
                using (ConnectionMultiplexer redis = ConnectionMultiplexer.Connect("localhost:6379"))
                {
                    IDatabase db = redis.GetDatabase();
                    ITransaction tran = db.CreateTransaction();
                    //为该事务添加先决条件
                    //强制指定指定的哈希字段不能存在。
                     tran.AddCondition(Condition.HashNotExists("transactionDemo", "UniqueID"));
                    tran.HashSetAsync("transactionDemo", "UniqueID","Unnn");
                    bool committed = tran.Execute();
                    Console.WriteLine(committed); //第1次执行,true,因为不存在,后面执行false,因为存在
                }
            }
    

    通过 When 的内置操作

    还应该注意的是,Redis已经为我们预料到了许多常见的场景(特别是:key/hash的存在,就像上面一样),还有单操作(single-operation)原子命令的存在。 通过 When 来访问,所以前面的示例也可以这样来实现:

    var newId = CreateNewId();
    bool wasSet = db.HashSet(custKey, "UniqueID", newId, When.NotExists);
    

    注意:When.NotExists 会使用命令 HSETNX 而不会使用 HSET
    HSETNX:如果字段已经存在于哈希表中,操作无效。

  • 相关阅读:
    [Linux起步]常用命令
    Eclipse被SD杂志评为最佳开源工具
    [一点一滴学英语]20050921
    [一点一滴学英语]20050920
    [一点一滴学英语]20050919
    Longhorn (Vista) 推迟发布的背后
    最快速度找到内存泄漏
    重载(overload)、覆盖(override)、隐藏(hide) 详解
    HTTP请求和响应格式
    Skia之四——SkGradientShader篇
  • 原文地址:https://www.cnblogs.com/tangge/p/10753859.html
Copyright © 2011-2022 走看看