Redis事务
可以一次执行多个命令,本质是一组命令的集合。一个事务中的所有命令都会序列化,按顺序地串行化而不会被其他命令插入,不许加塞
能干嘛?
一个队列中,一次性、顺序性、排他性的执行一系列命令
redis事务 vs 数据库事务
1 单独的隔离操作 | Redis的事务仅仅是保证事务里的操作会被连续独占的执行,redis命令执行是单线程架构,在执行完事务内所有指令前是不可能再去同时执行其他客户端的请求的 |
---|---|
2 没有隔离级别的概念 | 因为事务提交前任何指令都不会被实际执行,也就不存在”事务内的查询要看到事务里的更新,在事务外查询不能看到”这种问题了 |
3不保证原子性 | Redis的事务不保证原子性,也就是不保证所有指令同时成功或同时失败,只有决定是否开始执行全部指令的能力,没有执行到一半进行回滚的能力 |
4 排它性 | Redis会保证一个事务内的命令依次执行,而不会被其它命令插入 |
常用命令
序号 | 描述 |
---|---|
1 | discard:取消事务,放弃执行事务块内的所以命令 |
2 | exec:执行所有事务块内的命令 |
3 | multi:标记一个事务块的开始 |
4 | unwatch:取消watch命令对所有key的监视 |
5 | watch key [key....]:监视一个(或多个)key,如果在事务执行之前这个(或这些)key 被其他命令所改动,那么事务将被打断 |
正常执行(multi(开启事务)+exec(执行事务))
放弃事务(discard)
在事务中数据报错都不会执行
在事务中数据报错了,不影响别的数据执行
Redis不提供事务回滚的功能,开发者必须在事务执行出错后,自行恢复数据库状态
注意:
redis
事务和传统数据库事务区别,不一定要么一起成功要么一起失败
监控(watch)
redis
使用watch来提供乐观锁定,类似与CAS
(check-and-set
)
- 悲观锁:
- 悲观锁(Pessimistic Lock), 顾名思义,就是很悲观,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会block直到它拿到锁。
- 乐观锁:
- 乐观锁(Optimistic Lock), 顾名思义,就是很乐观,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据。
- 乐观锁策略:提交版本必须 大于 记录当前版本才能执行更新
- CAS:
- 在 Redis 中,CAS(Check-And-Set)是一种使用乐观锁来保证数据一致性的方法。它的基本思想是:在执行某个操作之前,先检查数据是否被其他客户端修改过,如果没有,则执行操作;如果有,则放弃操作并重试。
watch:初始化 k1 和 balance 两个 key,先监控在开启 multi
,保证两 key 变动在同一事务内
有加塞篡改
unwatch
用于取消 WATCH 命令对所有 key 的监视。
一旦执行了exec之前加的监控锁都会被取消掉了
当客户端连接丢失的时候(比如退出链接),所有东西都会被取消监视
总结
- 开启:以
multi
开始一个事务 - 入队:将多个命令入队到事务中,接到这些命令并不会立即执行,而是放到等待执行的事务队列里面
- 执行:由
exec
命令触发事务
Redis管道(Pipeline)
Redis是一种基于客户端-服务端模型以及请求/响应协议的TCP服务。一个请求会遵循以下步骤:
1 客户端向服务端发送命令分四步(发送命令→命令排队→命令执行→返回结果),并监听Socket返回,通常以阻塞模式等待服务端响应。
2 服务端处理命令,并将结果返回给客户端。
上述两步称为:Round Trip Time(简称RTT,数据包往返于两端的时间),问题笔记最下方
如果同时需要执行大量的命令,那么就要等待上一条命令应答后再执行,这中间不仅仅多了RTT(Round Time Trip),而且还频繁调用系统IO,发送网络请求,同时需要redis调用多次read()和write()系统方法,系统方法会将数据从用户态转移到内核态,这样就会对进程上下文有比较大的影响了,性能不太好,o(╥﹏╥)o
管道是什么?
- Pipline 是为了解决 RTT 往返回时,仅仅是将命令一次性发送,对整个 Redis 的执行不造成其他任何影响
一句话:
- 批处理命令变化优化措施,类似 Redis 的原生批命令(mset和mget)
实例
一定要在 redis 外面执行
总结:
事务的原子性
- 原子性(Atomicity) 原子性是指事务包含的所有操作要么全部成功,要么全部失败回滚,因此事务的操作如果成功就必须要完全应用到数据库,如果操作失败则不能对数据库有任何影响。
- 一致性(Consistency) 事务开始前和结束后,数据库的完整性约束没有被破坏。比如A向B转账,不可能A扣了钱,B却没收到。
- 隔离性(Isolation) 隔离性是当多个用户并发访问数据库时,比如操作同一张表时,数据库为每一个用户开启的事务,不能被其他事务的操作所干扰,多个并发事务之间要相互隔离。 同一时间,只允许一个事务请求同一数据,不同的事务之间彼此没有任何干扰。比如A正在从一张银行卡中取钱,在A取钱的过程结束前,B不能向这张卡转账。
- 持久性(Durability) 持久性是指一个事务一旦被提交了,那么对数据库中的数据的改变就是永久性的,即便是在数据库系统遇到故障的情况下也不会丢失提交事务的操作。
Pipeline与原生批处理命令对比
- 原生批量命令是原子性(例如:mset、mget),pipeline 是非原子性
- 原生批量命令一次只能执行一种命令,pipeline支持批量执行不同命令
- 原生批命令是服务端实现的,而pipeline需要服务端与客户端共同完成
Pipeline 与事务对比
- 事务具有原子性,管道不具有原子性
- 管道一次性将多个命令发送到服务器,事务是一条一条的发,事务只有在接收到exec命令后才会执行,管道不会
- 执行事务时会阻塞其他命令的执行,而执行管道中的命令时不会
使用Pipeline注意事项
- pipeline 缓冲的指令只是会依次执行,不保证原子性,如果执行中指令发送异常,将会继续执行后续的指令
- 使用 pipeline 组装的命令个数不能太多,不然数据量过大客户端阻塞的时间可能过久,同时服务端此时也被迫回复一个队列答复,占用很多内存。