事务
关于事务,我们可能更熟悉 MySQL 的事务,这里先介绍 MySQL 事务的四大特性
- 原子性:把多个操作打包成一个整体,要么全部执行成功,要么全部执行失败。如果执行到中间的操作,失败了则需要把前面操作进行回退
- 一致性:事务执行之前和之后,数据不会出错
- 持久性:事务所做的修改都会保存硬盘
- 隔离性:事务并发执行涉及的一些问题,比如一个事务执行过程中是否可以看到另一个事务执行中或执行后的结果
Redis 的事务在概念上和 MySQL 事务是类似的,都是把一系列操作绑定成一组,让这一组能够批量执行
但要注意二者的区别:
Redis 事务
- 弱原子性:Redis 没有
回滚机制
,只能做到打包批量执行
,不能做到一个失败就恢复到初始状态 - 不保证一致性:不涉及
约束
,也没有回滚,MySQL 的一致性是体现在事务运行前和运行后,结果都合理有效,不会出现中间非法状态 - 不需要持久性:数据保存在内存中,虽然有持久化,但是是服务端对数据的持久化,和事务无关
- 没有隔离性:没有隔离级别,因为 Redis 是单线程,并不会并发执行事务
Redis 事务本质是,服务器给每个客户端准备一个事务队列
,客户端开启事务后,执行的每一个操作,服务端会先放到事务队列
中,并不会立即执行
在客户端结束事务后,服务端将该客户端事务队列
中的操作按照顺序依次执行
因此,Redis 的事务相比 MySQL,是弱化很多的,只能保证
打包批量执行
,不会被其他客户端抢占
因为 Redis 更注重效率,所以没有将事务设计的全面和复杂,MySQL 事务强大的背后是更多的空间和时间开销
使用
首先,Redis 是支持
lua
脚本的,可以通过 lua + 事务适配更好的并发场景
其次,集群模式下,Redis 是不支持事务的
命令
MULTI 开启事务
开启一个事务,执行成功返回 OK
127.0.0.1:6379> multi
OK
事务中的命令都会被添加到服务端的事务队列
此时其他 redis 客户端看不到执行命令的结果,因为命令其实还没执行
而本客户端也看不到此时的数据,因为所有命令都会被添加到事务队列
,并为执行,所以不会得到服务端响应
127.0.0.1:6379> multi
OK
127.0.0.1:6379> set key1 111
QUEUED
127.0.0.1:6379> set key2 222
QUEUED
127.0.0.1:6379> set key3 333
QUEUED
127.0.0.1:6379> keys *
QUEUED
每次添加一个操作,都会提示QUEUED
,说明命令已经进入客户端队列
EXEC 执行事务
服务端收到该命令后,将该客户端事务队列
的命令按顺序执行
127.0.0.1:6379> multi
OK
127.0.0.1:6379> set key1 111
QUEUED
127.0.0.1:6379> set key2 222
QUEUED
127.0.0.1:6379> set key3 333
QUEUED
127.0.0.1:6379> keys *
QUEUED
127.0.0.1:6379> exec
1) OK
2) OK
3) OK
4) 1) "key1"
2) "key"
3) "x"
4) "key2"
5) "key3"
DISCARD 放弃事务
放弃当前事务,此时直接情况事务队列
,之前的操作并不会真正执行
127.0.0.:16379> multi
OK
127.0.0.:16379> set k1 1
QUEUED
127.0.0.:16379> set k2 2
QUEUED
127.0.0.:16379> discard
OK
当开启事务后,并且有事务队列
有若干命令时,如果服务器重启或者挂掉,那么事务会被丢弃,效果等同于 discard
WATCH
可能会有如下场景:
虽然从时间轴上看,是客户端1先对 key 进行修改,但是因为执行事务的时机比客户端2晚,所以实际修改是客户端1后于客户端2
这可能会造成数据上的错误,Redis 通过watch
规避这类场景的出现
watch
用于监控一个 key 是否在执行事务期间被其他客户端修改,如果修改,那么最后执行事务时会报错,不执行事务
watch
底层是通过给 key 分配版本号实现监控效果,流程如下:
- 在执行事务前,对 key 进行 watch,分配一个版本号并记录
- 开启事务
- multi之后,exec 之前,如果有其他客户端对 watch 的 key 进行了修改,那么其版本号会变大
- 执行 exec后,不管事务期间有没有对监控的 key 进行修改,都会判断其版本号与记录是否相同,相同则说明没有其他客户端对其进行修改,事务执行成功;反之如果版本号不同,则不实际执行事务,返回
nil
小结
Redis 的事务相比 MySQL 简单很多
- 弱原子性:只有将操作打包执行,不支持回滚操作
- 不保证一致性:不保证事务执行前后的数据一致
- 不保证持久性:通过内存存储数据,没有持久性
- 不保证隔离性:Redis 为单机服务、单线程的服务器模型,串行执行命令
multi
:开启事务
exec
:事务结束,实际执行事务
discard
:放弃当前事务
watch / unwatch
:监控 key / 取消监控 key
Redis 支持 lua 脚本,也可以通过 lua 脚本实现事务
以上就是本篇博客的所有内容,感谢你的阅读
如果觉得本篇文章对你有所帮助的话,不妨点个赞支持一下博主,拜托啦,这对我真的很重要。