Redis事务控制
Redis 事务控制
1、Redis 事务控制的相关命令
命令名 | 作用 |
---|---|
MULTI | 表示开始收集命令,后面所有命令都不是马上执行,而是加入到一个队列中。 |
EXEC | 执行 MULTI 后面命令队列中的所有命令。 |
DISCARD | 放弃执行队列中的命令。 |
WATCH | “观察“、”监控“一个 KEY,在当前队列外的其他命令操作这个 KEY 时,放弃执行自己队列的命令 |
UNWATCH | 放弃监控一个 KEY |
2、命令队列执行失败的两种情况
① 加入队列时失败
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> set number 1000
QUEUED
127.0.0.1:6379> INCRBY number 10
QUEUED
127.0.0.1:6379> INCRBY number 10
QUEUED
127.0.0.1:6379> INCRBY number 10
QUEUED
127.0.0.1:6379> exec
OK
(integer) 1010
(integer) 1020
(integer) 1030
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> set number 10000
QUEUED
127.0.0.1:6379> INCRBY number 100
QUEUED
127.0.0.1:6379> INCRBY number 100
QUEUED
127.0.0.1:6379> INCRBY number 100 100
(error) ERR wrong number of arguments for ‘incrby’ command
127.0.0.1:6379> exec
(error) EXECABORT Transaction discarded because of previous errors.
127.0.0.1:6379> get number
“1030”
遇到了入队时即可检测到的错误,整个队列都不会执行。
② 执行队列时失败
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> set age 999
QUEUED
127.0.0.1:6379> DECRBY age 1
QUEUED
127.0.0.1:6379> DECRBY age 1
QUEUED
127.0.0.1:6379> DECRBY age a
QUEUED
127.0.0.1:6379> DECRBY age 1
QUEUED127.0.0.1:6379> EXEC
- OK
- (integer) 998
- (integer) 997
- (error) ERR value is not an integer or out of range
- (integer) 996
错误在入队时检测不出来,整个队列执行时有错的命令执行失败,但是其他命令并没有回滚。
③Redis 为什么不支持回滚
官方解释如下:
如果你有使用关系式数据库的经验, 那么 “Redis 在事务失败时不进行回滚,而是继续执行余下的命令”这种做法可能会让你觉得有点奇怪。以下是这种做法的优点:
1.Redis 命令只会因为错误的语法而失败(并且这些问题不能在入队时发现),或是命令用在了错误类型的键上面:这也就是说,从实用性的角度来说,失败的命令是由编程错误造成的,而这些错误应该在开发的过程中被发现,而不应该出现在生产环境中。 2.因为不需要对回滚进行支持,所以 Redis 的内部可以保持简单且快速。
有种观点认为 Redis 处理事务的做法会产生 bug , 然而需要注意的是, 在通常情况下, 回滚并不能解决编程错误带来的问题。 举个例子, 如果你本来想通过 INCR 命令将键的值加上 1 , 却不小心加上了 2 , 又或者对错误类型的键执行了 INCR , 回滚是没有办法处理这些情况的。
3、悲观锁和乐观锁
在使用 WATCH 命令监控一个 KEY 后,当前队列中的命令会由于外部命令的执行而放弃,这是乐观锁的体现。
开启两个命令窗口,分别使用 watch 监控同一个 key。上方的命令先执行 EXEC,则 MULTI 后面命令队列中的所有命令都被执行了。而下面的命令后执行 EXEC,返回结果 nil。
悲观锁
认为当前环境非常容易发生碰撞,所以执行操作前需要把数据锁定,操作完成后释放锁,其他操作才可以继续操作。
乐观锁
认为当前环境不容易发生碰撞,所以执行操作前不锁定数据,万一碰撞真的发生了,那么检查版本号:
- 如果是基于最新的版本所做的修改:服务器接受,修改成功
- 如果是基于旧的版本号所做的修改:服务器不接受,修改失败,整个 MULTI 队列中的操作都被丢弃