Redis的事务

Posted 开心ever

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Redis的事务相关的知识,希望对你有一定的参考价值。

事务

MULTI 、 EXEC 、 DISCARD 和 WATCH 是 Redis 事务相关的命令。事务可以一次执行多个命令, 并且带有以下两个重要的保证:

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

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

EXEC 命令负责触发并执行事务中的所有命令:

  如果客户端在使用 MULTI 开启了一个事务之后,却因为断线而没有成功执行 EXEC ,那么事务中的所有命令都不会被执行。

  另一方面,如果客户端成功在开启事务之后执行 EXEC ,那么事务中的所有命令都会被执行。

当使用 AOF 方式做持久化的时候, Redis 会使用单个 write(2) 命令将事务写入到磁盘中。

然而,如果 Redis 服务器因为某些原因被管理员杀死,或者遇上某种硬件故障,那么可能只有部分事务命令会被成功写入到磁盘中。

如果 Redis 在重新启动时发现 AOF 文件出了这样的问题,那么它会退出,并汇报一个错误。

使用redis-check-aof程序可以修复这一问题:它会移除 AOF 文件中不完整事务的信息,确保服务器可以顺利启动。

从 2.2 版本开始,Redis 还可以通过乐观锁(optimistic lock)实现 CAS (check-and-set)操作,具体信息请参考文档的后半部分

以上摘自官网

事务到底是什么?

可以一次执行多个命令,本质是一组命令的集合。一个事务中的所有命令都会序列化,按顺序地串行化执行而不会被其它命令插入,不许加塞

能干嘛

一个队列中,一次性、顺序性、排他性的执行一系列命令

操作方法/案例

  • 常用命令

  

[root@izuf6hmkcpexishpa3id8xz ~]# cd redis-5.0.5
[root@izuf6hmkcpexishpa3id8xz redis-5.0.5]# src/redis-cli 
127.0.0.1:6379> ping
PONG
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> set id 12
QUEUED
127.0.0.1:6379> get id
QUEUED
127.0.0.1:6379> incr t1
QUEUED
127.0.0.1:6379> incr t1
QUEUED
127.0.0.1:6379> get t1
QUEUED
127.0.0.1:6379> EXEC
1) OK
3) "12"
4) (integer) 1
5) (integer) 2
6) "2"
127.0.0.1:6379> 

 

  • Case2:放弃事务

127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> set name z3
QUEUED
127.0.0.1:6379> set age 28
QUEUED
127.0.0.1:6379> incr t1
QUEUED
127.0.0.1:6379> discard
OK
127.0.0.1:6379> 
  • Case3:全体连坐

127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> set name z3
QUEUED
127.0.0.1:6379> get name 
QUEUED
127.0.0.1:6379> incr t1
QUEUED
127.0.0.1:6379> get t1
QUEUED
127.0.0.1:6379> set email
(error) ERR wrong number of arguments for \'set\' command
127.0.0.1:6379> EXEC
(error) EXECABORT Transaction discarded because of previous errors.#一个错误全体连坐,都不执行
127.0.0.1:6379> 
  • Case4:冤头债主

127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> set age 11
QUEUED
127.0.0.1:6379> incr t1
QUEUED
127.0.0.1:6379> set email abc@163.com
QUEUED
127.0.0.1:6379> incr email
QUEUED
127.0.0.1:6379> get age
QUEUED
127.0.0.1:6379> EXEC
1) OK
2) (integer) 3
3) OK
4) (error) ERR value is not an integer or out of range
5) "11"
127.0.0.1:6379> 
  • Case5:watch监控

    1. 悲观锁/乐观锁/CAS(Check And Set)
        • 悲观锁

          悲观锁(Pessimistic Lock), 顾名思义,就是很悲观,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会block直到它拿到锁。

          传统的关系型数据库里边就用到了很多这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁

         

        • 乐观锁

          乐观锁(Optimistic Lock), 顾名思义,就是很乐观,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号等机制。

          乐观锁适用于多读的应用类型,这样可以提高吞吐量

          乐观锁策略:提交版本必须大于记录当前版本才能执行更新

        • CAS

                   2.初始化信用卡可用余额和欠额

127.0.0.1:6379> set balace 100
OK
127.0.0.1:6379> set debt 0
OK
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> DECRBY balace 30
QUEUED
127.0.0.1:6379> INCRBY debt 30
QUEUED
127.0.0.1:6379> EXEC
1) (integer) 70
2) (integer) 30
127.0.0.1:6379> get balace
"70"
127.0.0.1:6379> get debt
"30"
127.0.0.1:6379> 

    3.无加塞篡改,先监控再开启multi,保证两笔金额变动在同一个事务内

127.0.0.1:6379> WATCH balace
OK
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> DECRBY balace 10
QUEUED
127.0.0.1:6379> INCRBY debt 10
QUEUED
127.0.0.1:6379> EXEC
1) (integer) 60
2) (integer) 40
127.0.0.1:6379> 

    4.有加塞篡改

      监控了key,如果key被修改了,后面一个事务的执行失效

127.0.0.1:6379> WATCH balace
OK
127.0.0.1:6379> set balace 300 #修改
OK
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> DECRBY balace 15 #操作
QUEUED
127.0.0.1:6379> INCRBY debt 15
QUEUED
127.0.0.1:6379> EXEC
(nil)
127.0.0.1:6379> get balace #因为改了 所以操作失效
"300"
127.0.0.1:6379> 

    5.unwatch

127.0.0.1:6379> WATCH balace
OK
127.0.0.1:6379> set balace 300
OK
127.0.0.1:6379> set balace 350
OK
127.0.0.1:6379> UNWATCH
OK
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> set balace 100
QUEUED
127.0.0.1:6379> set debt 0
QUEUED
127.0.0.1:6379> EXEC
1) OK
2) OK
127.0.0.1:6379> get balace
"100"

    6.一旦执行了exec之前加的监控锁都会被取消掉了

    7.小结

      • Watch指令,类似乐观锁,事务提交时,如果Key的值已被别的客户端改变,
        比如某个list已被别的客户端push/pop过了,整个事务队列都不会被执行

      • 通过WATCH命令在事务执行之前监控了多个Keys,倘若在WATCH之后有任何Key的值发生了变化,
        EXEC命令执行的事务都将被放弃,同时返回Nullmulti-bulk应答以通知调用者事务执行失

  • 3阶段

    1.开启:以MULTI开始一个事务

    2.入队:将多个命令入队到事务中,接到这些命令并不会立即执行,而是放到等待执行的事务队列里面

    3.执行:由EXEC命令触发事务  

  • 3特性

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

    2.没有隔离级别的概念:队列中的命令没有提交之前都不会实际的被执行,因为事务提交前任何指令都不会被实际执行,也就不存在”事务内的查询要看到事务里的更新,在事务外查询不能看到”这个让人万分头痛的问题

    3.不保证原子性:redis同一个事务中如果有一条命令执行失败,其后的命令仍然会被执行,没有回滚

 

以上是关于Redis的事务的主要内容,如果未能解决你的问题,请参考以下文章

Redis源代码分析(十七)--- multi事务操作

redis代码解析-事务

19 事务 相关操作

19 事务 相关操作

Redis事务入门及命令

Redis事务入门及命令