时间:2022-10-20 09:38:42
在 Redis 中使用 watch 命令可以决定事务是执行还是回滚。一般而言,可以在 multi 命令之前使用 watch 命令监控某些键值对,然后使用 multi 命令开启事务,执行各类对数据结构进行操作的命令,这个时候这些命令就会进入队列。
当 Redis 使用 exec 命令执行事务的时候,它首先会去比对被 watch 命令所监控的键值对,如果没有发生变化,那么它会执行事务队列中的命令,提交事务;如果发生变化,那么它不会执行任何事务中的命令,而去事务回滚。无论事务是否回滚,Redis 都会去取消执行事务前的 watch 命令,这个过程如图 1 所示。
Redis 在执行事务的过程中,并不会阻塞其他连接的并发,而只是通过比较 watch 监控的键值对去保证数据的一致性,所以 Redis 多个事务完全可以在非阻塞的多线程环境中并发执行,而且 Redis 的机制是不会产生 ABA 问题的,这样就有利于在保证数据一致的基础上,提高高并发系统的数据读/写性能。
Redis事务常用命令:
序号 | 命令及描述 |
---|---|
1 | DISCARD 取消事务,放弃执行事务块内的所有命令。 |
2 | EXEC 执行所有事务块内的命令。 |
3 | MULTI 标记一个事务块的开始。 |
4 | UNWATCH 取消 WATCH 命令对所有 key 的监视。 |
5 | WATCH key [key ...] 监视一个(或多个) key ,如果在事务执行之前这个(或这些) key 被其他命令所改动,那么事务将被打断。 |
下面演示一个成功提交的事务:
这里我们使用了 watch 命令设置了一个 test1 的监控,然后开启事务设置 test2,直至 exec 命令去执行事务,这个过程和图 2 所演示的一样。
序号 | 执行命令 | 描述 |
---|---|---|
t1 | flushdb | 清空所有数据慎重 |
t2 | set test1 1 | 初始化test1的值 |
t3 | watch test1 | 监控 test1 的键值对 |
t4 | multi | 开启事务 |
t5 | set test2 2 | 设置test2的值(加入事务队列) |
t6 | exec | 提交事务,可对结果进行判断 |
t7 | get test2 | 获取test2的值 |
下面演示一个不成功的提交的事务:
序号 | 线程1命令 | 线程2命令 | 描述 |
---|---|---|---|
t1 | flushdb | 清空所有数据慎重 | |
t2 | set test1 1 | 初始化test1的值 | |
t3 | watch test1 | 监控 test1 的键值对 | |
t4 | set test1 11 | 变更被监控的test1键值对 | |
t5 | multi | 开启事务 | |
t6 | set test2 2 | 设置test2的值(加入事务队列) | |
t7 | exec | 执行事务,但是事务会先检査在t3 时刻被监控的 test1 是否被其修改过。 因为线程2 修改过,所以它会回滚事务,事实上如果某线程执行的是 set test1 value1 命令,它也会认为 key1 被修改过,然后返回(nil),所以是不会产生 ABA 问题的 | |
t8 | get test1 | 获取test1的值 |