Redis

一、Redis 事务

Redis 事务可以一次执行多个命令, 并且带有以下两个重要的保证:

● 事务是一个单独的隔离操作事务中的所有命令都会序列化、按顺序地执行。事务在执行的过程中,不会被其他客户端发送来的命令请求所打断

● 事务是一个原子操作事务中的命令要么全部被执行,要么全部都不执行。

一个事务从开始到执行会经历以下三个阶段:

● 开始事务(MULTI)

● 命令入队

● 执行事务(EXEC)

二、Redis事务命令

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

DISCARD:取消事务,放弃执行事务块内的所有命令。

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

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

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

三、事务执行

● 正常执行事务

127.0.0.1:6379> MULTI        // 开启事务
OK
// 命令入队
127.0.0.1:6379> set k1 v1
QUEUED
127.0.0.1:6379> set k2 v2
QUEUED
127.0.0.1:6379> get k2
QUEUED
127.0.0.1:6379> set k3 v3
QUEUED
127.0.0.1:6379> EXEC        // 执行事务
1) OK
2) OK
3) "v2"
4) OK

● 放弃事务

127.0.0.1:6379> MULTI  // 开启事务
OK
127.0.0.1:6379> set k1 v1
QUEUED
127.0.0.1:6379> set k4 v4
QUEUED
127.0.0.1:6379> set k6 v6
QUEUED
127.0.0.1:6379> DISCARD  // 取消事务
OK
127.0.0.1:6379> get k6   // 事务队列中的命令都不会被执行
(nil)

- 编译时异常(代码有错,命令有错误):事务中所有的命令都不会被执行

127.0.0.1:6379> MULTI  // 开启事务
OK
127.0.0.1:6379> set k1 v1
QUEUED
127.0.0.1:6379> set k2 v2
QUEUED
127.0.0.1:6379> getset k2  // 错误命令
(error) ERR wrong number of arguments for 'getset' command
127.0.0.1:6379> set k4 v4
QUEUED
127.0.0.1:6379> EXEC  // 执行事务报错
(error) EXECABORT Transaction discarded because of previous errors.
127.0.0.1:6379> get k1  // 所有命令都不会被执行
(nil)

- 运行时异常(语法错误):如果事务队列存在语法性错误,在执行的时候其它命令可以正常执行

127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> set k1 v1
QUEUED
127.0.0.1:6379> INCR k1// 执行的时候失败
QUEUED
127.0.0.1:6379> set k2 v2
QUEUED
127.0.0.1:6379> set k3 v3
QUEUED
127.0.0.1:6379> get k2
QUEUED
127.0.0.1:6379> get k1
QUEUED
127.0.0.1:6379> EXEC
1) OK
2) (error) ERR value is not an integer or out of range// 虽然该命令报错,但是其它命令依旧执行成功!
3) OK
4) OK
5) "v2"
6) "v1"

四、监控 - WATCH

● 悲观锁:很悲观,认为什么时候都会出现问题,无论做什么都会加锁!

● 乐观锁:很乐观,认为什么时候都不会出现问题,所以不会上锁!更新数据的时候去判断一下,在此期间是否有人修改过这个数据

● 测试 - 正常执行成功

127.0.0.1:6379> set money 100
OK
127.0.0.1:6379> set out 0
OK
127.0.0.1:6379> WATCH money  // 监视money对象
OK
127.0.0.1:6379> MULTI      // 事务正常结束,数据期间没有发生变动,这个时候就正常执行成功!
OK
127.0.0.1:6379> DECRBY money 20
QUEUED
127.0.0.1:6379> INCRBY out 20
QUEUED
127.0.0.1:6379> EXEC
1) (integer) 80
2) (integer) 20

● 测试 - 多线程修改值,使用watch可以当做redis的乐观锁!

127.0.0.1:6379> WATCH money out  // 监视money out
OK
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> INCRBY out 10
QUEUED
127.0.0.1:6379> DECRBY money 10
QUEUED
127.0.0.1:6379> EXEC         // 执行之前,另一个线程,修改了监视对象的值,会导致事务执行失败
(nil)

如果修改失败,获取最新的值再次监视执行事务

127.0.0.1:6379> UNWATCH// 发现事务执行失败,取消监视
OK
127.0.0.1:6379> WATCH money out// 获取最新的值,再次监视(select version)
OK
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> INCRBY out 100
QUEUED
127.0.0.1:6379> DECRBY money 100
QUEUED
127.0.0.1:6379> EXEC// 最新的值没有被该事务之外的其它操作修改,执行成功!
1) (integer) 120
2) (integer) 980
原文地址:https://www.cnblogs.com/Dm920/p/12879456.html