初识Redis · 事务
目录
前言:
事务
涉及命令
前言:
前文我们花了大部分篇幅介绍了持久化,涉及到了RDB和AOF机制,涉及的文件有dump.rdb,appendonly.aof,涉及到的命令有save,bgsave,以及介绍了混合持久化的机制。并且理解了持久化主要是针对的Redis是一个内存级数据库的。
那么本文,我们就开始介绍一下Redis中的事务。
事务
提起事务,我们想必最开始想到的就是MySQL中的事务了,那么对于MySQL中的事务有四个特点,分别是:原子性,一致性,持久性,隔离性。
而Redis相较于MySQL来说,它的事务就是MySQL一个min版本的,我们从四个特点分别展开。
原子性
在我们学习线程的时候,我们知道原子性的意思是要么0要么1,反正没有中间态。在我们学习MySQL的时候,我们知道原子性代表的是要么全部执行成功,要么全部不执行。所以MySQL中如果有事务失败了,那么就会进行回滚操作,把中间执行的的操作全部退了。
对于原子性来说,MySQL无异于是拉高了原子性的门槛,所以咱们说起原子性的时候,不是想起线程就是MySQL,对于Redis来说咱们有的时候实在是想不起来。
而对于Redis来说,它是否具备原子性呢?我们先来看看旧版本Redis的截图
旧版本的Redis是认为Redis具有原子性的,可是新版本的Redis的介绍确实这样的:
默默的把具备原子性的这句话删除了。
这就比较有意思的,其实最开始的原子操作的意思是要么全部执行,要么全部不执行,Redis是做到了这个最开始的意思的,而MySQL将门槛拉高到了全部执行成功,这就让Redis比较尴尬了。
于是后面,官方就把原子性这句话给删除了,要怪就只能怪MySQL了。
一致性
Redis是不具备一致性的,因为Redis不像MySQL具备回滚机制,它执行错了也就错了,就不管结果如何了,反正执行完毕就行,那么数据不一致的问题,自然是会有的。
持久性
Redis也是不具备持久性的,这因为它本身就是一个内存级的数据库,自然没有持久性,你要说之前的持久化操作和这里的持久性是不是一个东西,因为这里的持久性是事务中的,持久化机制可和事务没有任何关系了。
隔离性
Redis也是不具备隔离性的,因为Redis的是一个单线程模型,所有的操作都是串行执行的,也就不涉及隔离性了。
那么究竟什么是事务呢?
我们举个通俗的例子:
A和B去吃烤肉,A先到地方,先点好了单,B还没来,A给老板说先等会儿,一会儿再烤,过了一会儿B来了,A给老板说可以烤了。
在这个过程中,A等待B的时候尽管有客人来了,但是老板已经将烤A那桌的肉计划到任务列表了,所以即便有人在A之后来,也不会有插队的形式表现。
即Redis的事务是把任务打包之后,要求执行的时候再执行。
那么比如618的时候,针对一个上商品的库存,就容易引发线程安全的问题,此时就要涉及到加锁等问题,如果使用Redis的事务,就不用那么麻烦了。
开启事务之后,引入任务,执行操作,这个过程就能完美避免因为线程安全导致的问题,把事务push到队列里,使用命令exec的时候服务器才执行,也就不会存在对count同时--的情况了。
不过Redis的事务应用场景没有MySQl那么多,并且如果是集群模式的Redis就不支持事务了。
涉及命令
以上是理论支撑,我们也得使用使用对应的命令不是?
涉及到的命令有MULTI,EXEC,DISCARD,WATCH,UNWATCH。
就这么多,MULTI是用来开启事务的,EXEC是用来执行事务的,DISCARD是用来丢弃事务的,WATCH是用来监视事务中的某个key的。
开启事务之后,我们输入set key1 111,此时我们另外启一个客户端,会发现查不了key1,此时我们再exec
exec代表执行事务,所以我们就能看到刚才入队列的事务成功被执行了,并且我们在另一个客户端也能查看到。
这也是一个非常形象的例子。
WATCH
是 Redis 提供的一种乐观锁机制,可以监视一个或多个 key,当你后续尝试执行事务(MULTI
-> EXEC
)时,如果 这些 key 在此期间被其他客户端修改过了,那么事务执行会失败(即 EXEC
返回 nil
)。
我们可以实验一下:
事务执行的时候,发现了key1被修改了,那么exec就拒绝执行了这次事务。
注意到是拒绝执行这次事务,所以我们设置的key2也没有执行成功。
✅ WATCH 的底层原理:
Redis 在每个 key 的元信息中维护一个“修改计数”,相当于一个隐式的版本号。当你 WATCH key
时:
-
Redis 把你 watch 的 key 加到客户端上下文中;
-
如果在你执行
EXEC
前,这些 key 被其他客户端修改(包括 SET/INCR/DEL 等),事务将失败; -
相当于检测“版本冲突”。
这种方式实现了乐观锁,适合低并发或业务层对失败有兜底机制的场景。
小结
Redis 的事务机制相较于传统数据库而言比较“轻量”:
-
不能回滚:中间命令失败不会影响其他命令;
-
没有隔离级别:单线程保证串行,但无事务隔离;
-
有乐观锁:WATCH 是一种简单但实用的乐观锁方案;
-
不适合复杂业务:对高并发、高一致性要求场景,推荐 Lua 脚本 或 落地数据库事务控制。
在日常开发中,如果你只是想保证一串命令的串行性和基本的并发控制,Redis 的事务还是挺好用的。
因为Redis中的事务本身的内容也就不多,所以这里也算是简单的理解了一下就过了。
感谢阅读!