V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
ifconfig
V2EX  ›  Redis

请教大佬们一个关于 redis 原子性的问题

  •  
  •   ifconfig · 2020-03-21 16:47:14 +08:00 · 6616 次点击
    这是一个创建于 1706 天前的主题,其中的信息可能已经有所发展或是发生改变。

    在学习 redis,突然发现有个疑问,先引用网上的一句话:

    单个 Redis 命令的执行是原子性的,但 Redis 没有在事务上增加任何维持原子性的机制,所以 Redis 事务的执行并不是原子性的。

    假设我先在 session-1 里执行:

    1 、WATCH name
    
    2 、MULTI
    
    3 、set name java
    

    然后,我再去到 session-2 里执行:

    1 、set name golang
    

    再回到 session-1 里执行

    4 、exec
    

    此时,session-1 返回(nil),说明事务回滚,那不就说明事务也保持了原子性吗?

    那为什么都说 redis 不具备原子性?谢谢各位大佬解答

    Jooooooooo
        1
    Jooooooooo  
       2020-03-21 16:54:16 +08:00
    redis 没有事务回滚的说法
    labulaka521
        2
    labulaka521  
       2020-03-21 17:06:33 +08:00 via Android
    这是 watch 的功能呀,如果执行 exec 时 watch 的值改变了,就不会执行了,
    ifconfig
        3
    ifconfig  
    OP
       2020-03-21 17:25:15 +08:00
    @labulaka521 是不是可以理解为,如果加了 watch,就没有执行,也就变相的达到了回滚的目的?
    ashmodeus
        4
    ashmodeus  
       2020-03-21 17:29:45 +08:00
    是不是这么理解更简单一些,类似于 SQL: UPDATE tblXXX SET name = 'java' WHERE name.version = lastVersion;
    huntcool001
        5
    huntcool001  
       2020-03-21 17:55:57 +08:00
    Redis 的这个事物和数据库的
    @ifconfig 是.

    但是限制就是,redis 的 MULTI EXEC 里, 只能引用 MULTI 之前已经确定的变量, 不能在 MULTI 里读取一个数,然后根据这个数做客户端这边的判断,然后再调用下一条指令. 而数据库里的事务是可以的. 所以我们说 Redis 的事务是个不完全的. 你如果想做成在事务中根据读出来的 Redis 里的某条数据再决定调用某个命令,就要写 lua 脚本了.(lua 脚本在 redis 服务端执行)

    参考:
    https://redis.io/topics/transactions
    https://redislabs.com/ebook/part-3-next-steps/chapter-11-scripting-redis-with-lua/11-3-doing-away-with-watchmultiexec/
    https://stackoverflow.com/questions/10750626/transactions-and-watch-statement-in-redis/10751198
    huntcool001
        6
    huntcool001  
       2020-03-21 17:56:55 +08:00
    *修订上一条, Redis 里的事务和关系型数据库里的不太一样.
    ifconfig
        7
    ifconfig  
    OP
       2020-03-21 17:58:07 +08:00
    @huntcool001 非常感谢,明白
    RedisMasterNode
        8
    RedisMasterNode  
       2020-03-21 18:00:07 +08:00 via Android
    所以其实正确来说,不应该讲 MULTI 解释为事务,正确的认识是使用 MULTI 使得多个命令可以串行执行不被打断,至于从准备到开始执行过程中是否有变更使用 WATCH 来检查,一旦开始执行就会全部执行完毕不被打扰
    huntcool001
        9
    huntcool001  
       2020-03-21 18:07:16 +08:00
    redis 的命令是具备原子性的.只是 redis 的事务不是完整的.

    另外, WATCH 其他比较常见的用法, 可以 WATCH 好几个 key, 任意一个有变化,紧接着的 MULTI....EXEC 就不会被执行. 还有就是,如果 WATCH 的 key 是自己 expire(过期了),后面的 MULTI .. EXEC 是不会回滚的.
    ifconfig
        10
    ifconfig  
    OP
       2020-03-21 18:11:21 +08:00
    @RedisMasterNode 真大佬,膜拜
    az467
        11
    az467  
       2020-03-21 21:45:12 +08:00
    返回 nil 只是说明 redis 根本没有执行此事务(命令队列)。
    按照官网的说法,redis 事务中的命令要么都被执行,要么都不被执行,所以它是有原子性的。

    什么?你说语法错误?语法出错了那不就是乱码吗?乱码又不是命令,无所谓执行不执行。
    不支持复杂操作?那跟原子性有关系么?
    没有自动回滚就不能拥有原子性,我 redis 并不认同(
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   5817 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 31ms · UTC 06:18 · PVG 14:18 · LAX 22:18 · JFK 01:18
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.