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监控
- 悲观锁/乐观锁/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的事务的主要内容,如果未能解决你的问题,请参考以下文章