学习目标:
1、了解Redis的事务的特性
2、了解Redis的事务的使用
学习过程:
事务的原理是先将属于一个事务的命令发送给redis ,然后再让 redis 依次执行这些命令,在redis中,事务的作用就是在一个队列中一次性、顺序性、排他性的执行一系列的命令。
事务的生命周期:
-
事务的创建:使用MULTI开启一个事务
-
加入队列:在开启事务的时候,每次操作的命令将会被插入到一个队列中,同时这个命令并不会被真的执行
-
EXEC命令进行提交事务, DISCARD:放弃事务,即该事务内的所有命令都将取消
常用的关于事务的命令有:
-
MULTI:使用该命令,标记一个事务块的开始,通常在执行之后会回复OK,(但不一定真的OK),这个时候用户可以输入多个操作来代替逐条操作,redis会将这些操作放入队列中。
-
EXEC:执行这个事务内的所有命令
-
DISCARD:放弃事务,即该事务内的所有命令都将取消
-
WATCH:监控一个或者多个key,如果这些key在提交事务(EXEC)之前被其他用户修改过,那么事务将执行失败,需要重新获取最新数据重头操作(类似于乐观锁)。
-
UNWATCH:取消WATCH命令对多有key的监控,所有监控锁将会被取消。
1、基本使用
示例代码:
执行事务
127.0.0.1:6379> multi
OK
127.0.0.1:6379> set key1 one
QUEUED
127.0.0.1:6379> INCR num1
QUEUED
127.0.0.1:6379> INCR num1
QUEUED
127.0.0.1:6379> set key2 two
QUEUED
127.0.0.1:6379> exec
1) OK
2) (integer) 1
3) (integer) 2
4) OK
127.0.0.1:6379> get num1
"2"
放弃事务示例:
当执行 DISCARD 命令时, 事务会被放弃, 事务队列会被清空, 并且客户端会从事务状态中退出:
> SET foo 1
OK
> MULTI
OK
> INCR foo
QUEUED
> DISCARD
OK
> GET foo
"1"
2、隔离测试,watch使用
隔离性需要和watch结合使用,redis不支持脏数据等级别的。 我们可以开启两个客户端,在exec之前,由另外一个客户端修改,看一下结果
第一个客户端
127.0.0.1:6379> watch num1
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> INCR num1
QUEUED
第二个客户端修改num1的值
[root@run1 bin]# ./redis-cli
127.0.0.1:6379> INCR num1
(integer) 214
第一个客户端执行事务
127.0.0.1:6379> exec
(nil)
127.0.0.1:6379> unwatch
OK
可以看到事务执行失败了。
3、不保证原子性的测试
看一下下面的例子,第二个执行虽然错误了,但是其他的命令都还是可以执行成功的。
127.0.0.1:6379> multi
OK
127.0.0.1:6379> set name liubao
QUEUED
127.0.0.1:6379> incr name
QUEUED
127.0.0.1:6379> incr num1
QUEUED
127.0.0.1:6379> incr num1
QUEUED
127.0.0.1:6379> exec
1) OK
2) (error) ERR value is not an integer or out of range
3) (integer) 211
4) (integer) 212
127.0.0.1:6379> get num1
"212"
但是如果入队的时候就发生了错误,那么所有的都不会执行的
127.0.0.1:6379> multi
OK
127.0.0.1:6379> incr num1
QUEUED
127.0.0.1:6379> abc
(error) ERR unknown command 'abc'
127.0.0.1:6379> exec
(error) EXECABORT Transaction discarded because of previous errors.
127.0.0.1:6379> get num1
"212"
总的来说redis事务的特点:Redis 事务可以做到保证一致性(C)和隔离性(I),但并不保证原子性(A)和持久性(D)。
-
单独的隔离操作:事务中的所有命令会被序列化、按顺序执行,在执行的过程中不会被其他客户端发送来的命令打断
-
没有隔离级别的概念:队列中的命令在事务没有被提交之前不会被实际执行
-
不保证原子性:redis中的一个事务中如果存在命令执行失败,那么其他命令依然会被执行,没有回滚机制