Redis:事务(Transactions)

简介: Redis事务支持将多个命令打包执行,但与MySQL不同,它不保证原子性、一致性、持久性和隔离性。Redis事务的核心在于“打包”命令,避免其他客户端插队,通过MULTI、EXEC、DISCARD等命令实现。此外,Redis提供WATCH和UNWATCH机制,用于监控键变化,实现类似“乐观锁”的功能,提升并发操作的安全性。

Redis事务(Transactions)

1,认识redis事务

redis的事务,类似于MySQL中的事务,但是相比于MySQL,redis的事务简单了不少。

关于MySQL中的事务,简单回顾下:


原子性:把多个操作打包成一个整体。


一致性:事务执行前后,数据都必须是正确的。


持久性:事务中做出的修改都会存硬盘,保证服务器在重启之后 ,数据仍然存在。


隔离性:事务的并发执行,会涉及到的一系列问题(比如脏读,幻读,不可重复读等)。

redis事务:


弱化原子性:MySQL的原子性,保证事务在执行过程中,要么全部执行成功,要么不执行,也就是有"回滚"操作。而redis事务的原子性,没有"回滚"进制,也就是redis也将一系列操作打包成一个事务,但是事务的执行结果是否正确,是不知道的。


没有一致性:redis没有约束,也没有"回滚"机制,事务在执行过程中,如果某个修改操作出现失败,就可能引起数据不一致的情况。


不具备持久性:redis本身是内存数据库,数据是存储在内存中的。redis本身也是具有持久化机制的,比如上面的RDB和AOF,但是这里的持久化,和事务没有关系。redis收到一条命令(或事务)是进行操作内存的,而MySQL是操作硬盘的。


不涉及隔离性:并发执行事务才会涉及到隔离性,而redis是单线程模型的服务器程序,所有的请求/事务,都是"串行"执行的。

2,redis事务的了解

redis的事务,主要的意义,就是"打包",避免其他客户端的命令,插队插到中间。


redis中实现事务,是引入了队列(每个客户端都有一个)。


开启事务的时候,此时客户端输入的命令,就会发给服务器并且进入这个队列中(而不是立即执行)。


当遇到了"执行事务"的命令,此时就会把队列中的这些命令按照顺序依次推送给服务器去执行。


3,相关命令

事务的开启与执行

开启事务:MULTI


执行事务:EXEC


放弃当前事务:DISCARD


WATCH和UNWATCH

在redis事务中,还提供了WATCH和UNWATCH两个命令。


首先引入下面的场景:


从时间上看,客户端1是先发送了set key 222,客户端2后发送了set key 333,按理来说应该是后发送的生效,也就是key的最终值是 333。


但实际上并非如此,由于客户端1中,必须是exec执行了,才会真正执行set key 222。因此这个操作变成了更晚的操作,所以key的最终值是222,而这也符合事务的特性。


此时就产生了歧义,这时就可以使用WATCH来监视这个key,看看这个key在事务的MULTI和EXEC之间,set key 之后,是否有外部 其他的客户端修改这个key。如果有,会给出提示。


相对的,还有一个UNWATCH命令,这个就是解除对某个key的监视。


效果演示:


在执行exec后,在执行上述事务中的命令时,发现key在外部有修改,那么在执行set key 222时,就没有真正执行,返回接轨是nil,不是ok。

WATCH的实现

WATCH是如何知道其他客户端修改了这个key呢?也就是WATCH是如何实现的。

WATCH的实现,类似于一个"乐观锁"。

所谓乐观锁和悲观锁,不是指某个具体的锁,而是指某一类锁的特性。


乐观锁:加锁之前,就有一个心理预期,预期接下来的锁冲突(锁竞争)概率比较低。


悲观锁:加锁之前 ,也有一个心理预期,预期接下来的锁冲突(锁竞争)概率比较高。


而锁冲突概率高,和所冲突概率低,接下来要做的工作是不一样的。

redis的WATCH就使用相当于"版本号"这样的机制,来实现了"乐观锁"。依旧是上面的例子,不过此时加上了WATCH来监控key 。

当执行WATCH的时候,就会给这个key安排一个"版本号",可以理解为一个整数。每次在修改这个key的时候,这个key的版本号就会变大。


所以当客户端2在执行set key 333时,就会修改这个key的版本号。


当客户端1执行到exec时,在执行事务中命令的时候,此时就会做出判定。判定当前key的版本号和最初WATCH时候记录的版本号是否一致。如果一致,说明当前key在事务开启到执行的整个过程中,没有其他客户端修改,于是才能进行真正的设置;如果发现不一致,说明key在其他客户端中改过了,因此此时就会丢弃该操作,exec返回一个nil。


所以,WATCH本质是给exec加了一个判定条件,这个过程也可以视作是一种加锁的过程。C++中的std::mutex,这是一个悲观锁,不满足条件会进行阻塞等待。而这里的锁,不满足条件就直接丢弃该操作,就相当于执行失败了。这个锁更加简单,也更加轻量,而出现上述情况的概率比较低,所以就没有使用像std::mutex这样复杂的机制,所以说WATCH的实现,类似于一个"乐观锁"。


相关文章
|
NoSQL Redis 数据库
10- 你们用过Redis的事务吗 ? 事务的命令有哪些 ?
```markdown Redis事务包括MULTI、EXEC、DISCARD、WATCH四个命令。虽具备事务功能,但在实际开发中使用较少。 ```
157 7
|
NoSQL Redis 数据库
什么是Redis的事务?
Redis事务提供原子性和顺序性,确保命令按顺序执行且不被打断。核心概念包括原子性、顺序性、隔离性和持久性。关键指令有MULTI、EXEC、DISCARD和WATCH,用于事务的开始、执行、取消和监视。这保障了命令的完整性,防止并发操作导致的数据不一致。
126 2
|
缓存 NoSQL 数据处理
Redis事务悄然而至:命令的背后故事
Redis事务悄然而至:命令的背后故事
106 0
|
12月前
|
缓存 NoSQL Redis
Redis 事务
10月更文挑战第18天
113 1
|
NoSQL Redis
Redis事务:保证数据操作的一致性和可靠性
Redis事务:保证数据操作的一致性和可靠性
249 0
|
负载均衡 NoSQL 算法
一天五道Java面试题----第十天(简述Redis事务实现--------->负载均衡算法、类型)
这篇文章是关于Java面试中Redis相关问题的笔记,包括Redis事务实现、集群方案、主从复制原理、CAP和BASE理论以及负载均衡算法和类型。
一天五道Java面试题----第十天(简述Redis事务实现--------->负载均衡算法、类型)
|
10月前
|
NoSQL Redis
Redis事务长什么样?一文带你全面了解
Redis事务是一组命令的有序队列,通过MULTI、EXEC、WATCH和DISCARD等命令实现原子性操作。事务中的命令在EXEC执行前不会实际运行,而是先进入队列,确保所有命令要么全部成功,要么全部失败。此外,Redis还支持Lua脚本实现类似事务的操作,通常更简单高效。事务适用于购物车结算、秒杀活动、排行榜更新等需要保证数据一致性的场景。
121 0
|
12月前
|
SQL 分布式计算 NoSQL
大数据-42 Redis 功能扩展 发布/订阅模式 事务相关的内容 Redis弱事务
大数据-42 Redis 功能扩展 发布/订阅模式 事务相关的内容 Redis弱事务
104 2
|
12月前
|
NoSQL 关系型数据库 MySQL
Redis 事务特性、原理、具体命令操作全方位诠释 —— 零基础可学习
本文全面阐述了Redis事务的特性、原理、具体命令操作,指出Redis事务具有原子性但不保证一致性、持久性和隔离性,并解释了Redis事务的适用场景和WATCH命令的乐观锁机制。
1295 0
Redis 事务特性、原理、具体命令操作全方位诠释 —— 零基础可学习
|
NoSQL 关系型数据库 Redis
Redis6入门到实战------ 九、10. Redis_事务_锁机制_秒杀
这篇文章深入探讨了Redis事务的概念、命令使用、错误处理机制以及乐观锁和悲观锁的应用,并通过WATCH/UNWATCH命令展示了事务中的锁机制。
Redis6入门到实战------ 九、10. Redis_事务_锁机制_秒杀