Redis事务

1、redis事务的基本概念

事务是指一个完整的动作,要么全部执行,要么什么也没有做。

Redis 事务不是严格意义上的事务,只是用于帮助用户在一个步骤中执行多个命令。单个 Redis 命令的执行是原子性的,但 Redis 没有在事务上增加任何维持原子性的机制,所以 Redis 事务的执行并不是原子性的。
Redis 事务可以理解为一个打包的批量执行脚本,但批量指令并非原子化的操作,中间某条指令的失败不会导致前面已做指令的回滚,也不会造成后续的指令不做。

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

1. 批量操作在发送 EXEC 命令前被放入队列缓存。
2. 收到 EXEC 命令后进入事务执行,事务中任意命令执行失败,其余的命令依然被执行。
3. 在事务执行过程,其他客户端提交的命令请求不会插入到事务执行命令序列中。

MULTI、EXEC、DISCARD、WATCH 这四个指令构成了 redis 事务处理的基础。

2、Redis事务VS数据库事务

在这里插入图片描述

3、Redis事务常用命令

命令描述
DISCARD取消事务,放弃执行事务块内的所有命令
EXEC执行所有事务块内的命令
MULTI标记一个事务块的开始
UNWATCH取消 WATCH 命令对所有 key 的监视
WATCH key [key …]监视一个(或多个) key ,如果在事务执行之前这个(或这些) key 被其他命令所改动,那么事务将被打断。

4、Redis事务实操

正常执行

127.0.0.1:6379> MULTI
OK
127.0.0.1:6379(TX)> set k1 v1
QUEUED
127.0.0.1:6379(TX)> set k2 v2
QUEUED
127.0.0.1:6379(TX)> keys *
QUEUED
127.0.0.1:6379(TX)> EXEC
1) OK			#表示第一条指令的执行结果
2) OK			#表示第二条指令的执行结果
3) 1) "k3"		#表示第三条指令的执行结果
   2) "k1"
   3) "k2"
127.0.0.1:6379> 

放弃事务

127.0.0.1:6379> get count
"1"
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379(TX)> INCR count
QUEUED
127.0.0.1:6379(TX)> INCR count
QUEUED
127.0.0.1:6379(TX)> DISCARD
OK
127.0.0.1:6379> get count
"1"
127.0.0.1:6379>

事务中出现错误怎么办?
看看官方文档怎么说:
在这里插入图片描述
大致的意思就是:
有关事务,大家经常会遇到的是两类错误:

  1. 调用 EXEC 之前的错误
  2. 调用 EXEC 之后的错误

调用 EXEC 之前的错误,有可能是由于语法有误导致的,也可能时由于内存不足导致的。只要出现某个命令无法成功写入缓冲队列的情况,redis 都会进行记录,在客户端调用 EXEC 时,redis 会拒绝执行这一事务

比如:

127.0.0.1:6379> MULTI
OK
127.0.0.1:6379(TX)> fl	//一个明显错误的指令
(error) ERR unknown command 'fl', with args beginning with: 
127.0.0.1:6379(TX)> set fl 22
QUEUED
127.0.0.1:6379(TX)> EXEC
//redis拒绝了事务的执行,原因是“之前出现了错误”
(error) EXECABORT Transaction discarded because of previous errors.
//因为redis拒绝了事务的执行,所以set fl 22并没有执行
127.0.0.1:6379> get fl
(nil)

于调用 EXEC 之后的错误,redis 则采取了完全不同的策略,即 redis 不会理睬这些错误,而是继续向下执行事务中的其他命令。这是因为,对于应用层面的错误,并不是 redis 自身需要考虑和处理的问题,所以一个事务中如果某一条命令执行失败,并不会影响接下来的其他命令的执行

比如:

127.0.0.1:6379> MULTI
OK
127.0.0.1:6379(TX)> set age 22
QUEUED
//age不是集合,所以如下是一条明显错误的指令
127.0.0.1:6379(TX)> sadd age fl
QUEUED
127.0.0.1:6379(TX)> set age 23
QUEUED
127.0.0.1:6379(TX)> EXEC	//执行事务时,redis不会理睬第2条指令执行错误
1) OK
2) (error) WRONGTYPE Operation against a key holding the wrong kind of value
3) OK
127.0.0.1:6379> get age
"23"	//可以看出第3条指令被成功执行了

注意和传统数据库的区别Redis不提供事务回滚的功能,开发者必须在事务执行出错后,自行恢复数据库状态

Redis使用WATCH来提供乐观锁定,类似于CAS(Check-and-Set)
WATCH 本身的作用是监视 key 是否被改动过,而且支持同时监视多个 key,只要还没真正触发事务,WATCH 都会尽职尽责的监视,一旦发现某个 key 被修改了,在执行 EXEC 时就会返回 nil,表示事务无法触发。

127.0.0.1:6379> set age 22
OK
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> watch age	//开始监视age
OK
127.0.0.1:6379> set age 23	//在EXEC之前,age的值被其他用户修改了
OK
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379(TX)> set age 24
QUEUED
127.0.0.1:6379(TX)> get age
QUEUED
127.0.0.1:6379(TX)> EXEC	//触发EXEC
(nil)	//事务无法被执行,因为在事务期间,age被其用户更改了
127.0.0.1:6379> get age
"23"

一旦执行了exec之前加的监控锁都会被取消掉。
当客户端连接丢失的时候(比如退出链接),所有东西都会被取消监视

如果不想再监控某个key,那就在开启事务之前使用命令UNWATCH取消监控

想想为什么redis不用悲观锁?而采用乐观锁?

如果redis采用悲观锁,那么redis就不可能是一个高性能的缓存数据库。因为它为了保证数据一致性,就会上锁,这样数据安全了,但并发性能就下降

在上述的这些例子中,我们看到了 QUEUED 的字样,这表示我们在用 MULTI 组装事务时,每一个命令都会进入到内存队列中缓存起来,如果出现 QUEUED 则表示我们这个命令成功插入了缓存队列,在将来执行 EXEC 时,这些被 QUEUED 的命令都会被组装成一个事务来执行。

对于事务的执行来说,如果 redis 开启了 AOF 持久化的话,那么一旦事务被成功执行,事务中的命令就会通过 write 命令一次性写到磁盘中去,如果在向磁盘中写的过程中恰好出现断电、硬件故障等问题,那么就可能出现只有部分命令进行了 AOF 持久化,这时 AOF 文件就会出现不完整的情况,这时,我们可以使用 redis-check-aof 工具来修复这一问题,这个工具会将 AOF 文件中不完整的信息移除,确保 AOF 文件完整可用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值