IT序号网

Redis的事务

wyy 2021年06月13日 数据库 229 0

事务

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同一个事务中如果有一条命令执行失败,其后的命令仍然会被执行,没有回滚


评论关闭
IT序号网

微信公众号号:IT虾米 (左侧二维码扫一扫)欢迎添加!

Redis的持久化下