单个 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 不具备原子性?谢谢各位大佬解答
1
Jooooooooo 2020-03-21 16:54:16 +08:00
redis 没有事务回滚的说法
|
2
labulaka521 2020-03-21 17:06:33 +08:00 via Android
这是 watch 的功能呀,如果执行 exec 时 watch 的值改变了,就不会执行了,
|
3
ifconfig OP @labulaka521 是不是可以理解为,如果加了 watch,就没有执行,也就变相的达到了回滚的目的?
|
4
ashmodeus 2020-03-21 17:29:45 +08:00
是不是这么理解更简单一些,类似于 SQL: UPDATE tblXXX SET name = 'java' WHERE name.version = lastVersion;
|
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 |
6
huntcool001 2020-03-21 17:56:55 +08:00
*修订上一条, Redis 里的事务和关系型数据库里的不太一样.
|
7
ifconfig OP @huntcool001 非常感谢,明白
|
8
RedisMasterNode 2020-03-21 18:00:07 +08:00 via Android
所以其实正确来说,不应该讲 MULTI 解释为事务,正确的认识是使用 MULTI 使得多个命令可以串行执行不被打断,至于从准备到开始执行过程中是否有变更使用 WATCH 来检查,一旦开始执行就会全部执行完毕不被打扰
|
9
huntcool001 2020-03-21 18:07:16 +08:00
redis 的命令是具备原子性的.只是 redis 的事务不是完整的.
另外, WATCH 其他比较常见的用法, 可以 WATCH 好几个 key, 任意一个有变化,紧接着的 MULTI....EXEC 就不会被执行. 还有就是,如果 WATCH 的 key 是自己 expire(过期了),后面的 MULTI .. EXEC 是不会回滚的. |
10
ifconfig OP @RedisMasterNode 真大佬,膜拜
|
11
az467 2020-03-21 21:45:12 +08:00
返回 nil 只是说明 redis 根本没有执行此事务(命令队列)。
按照官网的说法,redis 事务中的命令要么都被执行,要么都不被执行,所以它是有原子性的。 什么?你说语法错误?语法出错了那不就是乱码吗?乱码又不是命令,无所谓执行不执行。 不支持复杂操作?那跟原子性有关系么? 没有自动回滚就不能拥有原子性,我 redis 并不认同( |