redis 事务——迹忆客-ag捕鱼王app官网
redis 事务
redis中的事务可以理解成一个命令队列,该队列中的所有操作是一个整体,要么都执行,要么都不执行。所以我们可以认为redis中的事务是原子性的。 , , 和 四个命令是redis事务的基础。通过下面两个重要的保证,它允许在一个步骤中执行一组命令。
- 在一个事务中的所有的命令都被序列化并且顺序执行。它在中间执行的过程中不会被其他的客户端提交的命令所打断。这就保证了这些命令执行的独立性。
- 收到 exec 命令后进入事务执行,事务中的这些命令要么都执行,要么都不执行,所以我们可以认为redis中的事务是原子性的。
一个事务从开始到执行会经历以下三个阶段:
- 开始事务;
- 命令入队列;
- 执行事务;
在 redis 中,通过使用multi命令启动事务,然后需要传递应在事务中执行的命令列表,之后整个事务由exec命令执行。
示例
下面我们先用multi命令开启一个事务,然后在事务中添加几个命令,最后用exec命令来执行事务中添加的这些命令。
redis 127.0.0.1:6379> multi
ok
redis 127.0.0.1:6379> exec
(empty list or set)
redis 127.0.0.1:6379> multi
ok
redis 127.0.0.1:6379> set rediscomcn redis
queued
redis 127.0.0.1:6379> get rediscomcn
queued
redis 127.0.0.1:6379> incr visitors
queued
redis 127.0.0.1:6379> exec
1) ok
2) "redis"
3) (integer) 1
在上面的例子中,我们看到了 queued 的字样,这表示我们在用 multi 开启事务后,每一个命令都会进入到内存队列中缓存起来,如果出现 queued 则表示我们这个命令成功插入了缓存队列,在执行 exec 时,这些命令都会被依次执行。
如果中间的get rediscomcn
命令执行失败,此时的set rediscomcn redis已经执行成功,它不会再回滚,而下面的命令incr visitors
也照样会执行。
对于事务的执行来说,如果 redis 开启了 aof 持久化的话,那么一旦事务被成功执行,事务中的命令就会通过 write 命令一次性写到磁盘中去,如果在向磁盘中写的过程中恰好出现断电、硬件故障等问题,那么就可能出现只有部分命令进行了 aof 持久化,这时 aof 文件就会出现不完整的情况,这时,我们可以使用 redis-check-aof 工具来修复这一问题,这个工具会将 aof 文件中不完整的信息移除,确保 aof 文件完整可用。
事务中的错误
在整个事务期间,可能会遇到两种命令错误:
- 命令可能无法排队,因此在调用exec之前可能会出现错误。 例如,命令可能在语法上是错误的(错误的参数数量,错误的命令名称等),或者可能存在一些严重的情况,例如内存不足情况(如果服务器使用maxmemory配置为具有内存限制) 指示);
- 调用exec后,命令可能会执行失败,例如,因为我们对具有错误值的键执行了操作(如针对字符串值调用列表操作)。
客户端通常通过检查已排队命令的返回值来感知发生在exec调用之前的第一类错误:如果命令以queued答复,则它已正确排队,否则redis返回错误。 如果在排队时出现错误,大多数客户端将中止该事务并将其丢弃。
但是从redis 2.6.5开始,服务器将记住命令累积期间发生错误,并且将拒绝执行事务,同时在exec期间返回错误并自动丢弃该事务。 在redis 2.6.5之前,仅会执行在事务中成功排队命令,以防客户端直接调用exec而不管先前的错误如何。 这种新行为使将事务与流水线混合起来变得更加简单,因此可以一次发送整个事务,稍后再读取所有答复。
127.0.0.1:6379> multi
ok
127.0.0.1:6379> jiyik //一个明显错误的指令
(error) err unknown command 'haha'
127.0.0.1:6379> ping
queued
127.0.0.1:6379> exec
//redis拒绝了事务的执行,原因是“之前出现了错误”
(error) execabort transaction discarded because of previous errors.
相反,exec之后发生的错误不会以特殊方式处理:即使在事务期间某些命令失败,也会执行所有其他命令。
127.0.0.1:6379> multi
ok
127.0.0.1:6379> set age 10
queued
//age不是集合,所以如下是一条明显错误的指令
127.0.0.1:6379> sadd age 20
queued
127.0.0.1:6379> set age 30
queued
127.0.0.1:6379> 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
"30" //可以看出第3条指令被成功执行了
最后,我们来说说最后一个指令,这是一个很好用的指令,它可以帮我们实现类似于“乐观锁”的效果,即cas(check and set)。
watch 本身的作用是监视 key 是否被改动过,而且支持同时监视多个 key,只要还没真正触发事务,watch 都会尽职尽责的监视,一旦发现某个 key 被修改了,在执行 exec 时就会返回 nil,表示事务无法触发。
127.0.0.1:6379> set jiyik val1
ok
127.0.0.1:6379> watch jiyik //开始监视jiyik
ok
127.0.0.1:6379> set jiyik val2 //在exec之前,jiyik的值被修改了
ok
127.0.0.1:6379> multi
ok
127.0.0.1:6379> set jiyik val3
queued
127.0.0.1:6379> get jiyik
queued
127.0.0.1:6379> exec //触发exec
(nil) //事务无法被执行
相关命令
下表列出了 redis 事务的相关命令:
序号 | 命令 | 说明 |
---|---|---|
1 | 取消事务,放弃执行事务块内的所有命令 | |
2 | 执行所有事务块内的命令 | |
3 | 标记一个事务块的开始 | |
4 | 取消 watch 命令对所有 key 的监视 | |
5 | 监视一个(或多个) key |