5.2 Redis事务操作
5.2.1 事务的概念与ACID特性
ACID特性:
A:Atomicity,表示原子性.即事务是一个不可分割的实体,事务中的操作要么都做,要么全都不执行.
C:Consistency.表示一致性.即事务前后数据完整性必须一致,假设数据库里有很多完整性约束,比如ID字段不能为空,且必须是10位,在事务执行前后,这些完整性约束不能被违反
I:Isolation.即一个事务内部操对其他事务是隔离的,并发执行的各事务间不能互相干扰
D:Durability.指一个事务一旦提交,它对数据库的改变就是永久性的,哪怕数据库出现故障,事务执行后的操作也该丢失
5.2.2 实现Redis事务的相关命令
MULTI
功能:标记一个事务块的开始
DISCARD
功能:取消事务,放弃执行事务块内的所有命令
WATCH
语法:
WATCH key [key ...]
功能:监视一个(或多个)key,如果在事务执行之前这个(或这些)key被其他命令所改动,那么事务将被打断
UNWATCH
功能:取消
WATCH
命令对所有key的监控注意:该命令不能取消对指定键的监控,只能取消所有键的监控
注意:当你执行EXEC
或DISCARD
之后,Redis会自动取消对所有WATCH过的键的监视.所以,事务成功执行后(使用EXEC
)或放弃事务后(使用 DISCARD
),你不需要显式地调用UNWATCH
例:
对于命令SET name 'Peter'
而言,此时还没有开启事务,因此返回的结果是OK
然后通过MULTI
命令开启了事务.可以看到开启事务后,命令提示符尾部多了个(TX)
从SET id '001'
命令的返回值(QUEUED
)可以看出,该命令返回的结果并不是OK
,而是QUEUED
,表示该命令当前没有执行,而是放到了事务队列中
对于GET id
命令而言也是一样,该命令的返回值并不是id
对应的值,而是QUEUED
,同样表示该命令被放到了事务队列中
最终通过EXEC
命令执行事务.该命令会一次性地返回包含在事务队列中所有命令的执行结果.一旦执行完EXEC
命令,就退出了事务状态.因此可以看到GET age
命令会立即返回结果
本例表明:当通过MULTI
命令开启事务状态后,之后的命令不是立即执行,而是会被放入事务队列.当exec命令出现后,则会一次性地执行事务队列中的命令
5.2.3 通过DISCARD
命令撤销事务中的操作
DISCARD
命令撤销事务中的操作例:
注:开启事务前执行过FLUSHDB
可以看到,执行了DISCARD
命令后,退出了事务状态
在实际的应用中,如果能确保MULTI
后的命令均能正确执行,那么可以通过exec来提交事务;反之,则可以通过DISCARD
命令来撤销操作,以此体现事务的"原子性".
5.2.4 通过WATCH
命令监听键的变化
WATCH
命令监听键的变化注:本节使用的是我本地的redis,而非是容器中的redis
在Redis中,WATCH
命令是为了实现乐观锁提供的一种机制.它使得我们可以监视一个或多个键,然后根据这些键的值是否被其他客户端修改来决定是否继续执行事务.
乐观锁的核心思想是假设数据在大部分时间都不会产生冲突,因此先进行数据操作,如果后续发现数据有冲突(比如被其他客户端修改过)再进行相应的处理.
WATCH
的工作流程如下:
使用
WATCH
命令监视一个或多个键执行一系列命令,这些命令会基于你所监视的键的当前值
使用
MULTI
开始一个事务将你想在事务中执行的所有命令加入队列
使用
EXEC
命令尝试执行事务.如果从执行WATCH
命令开始,所监视的任何键都没有被其他客户端修改过,那么事务将成功执行.否则,事务将不执行任何命令并返回一个错误,告诉你有至少一个被监视的键已被修改
这个机制允许你确保在执行事务时,被监视的键的值与你上次检查时的值保持一致.
例如,考虑一个简单的场景,你想从一个键counter
中递增一个值,但只有在该值没有被更改过的情况下才这样做。你可以使用WATCH
来确保在你检查counter
值和递增它之间,没有其他客户端修改它
step1. 确保存在名为
counter
的键存在:
step2. 监视这个键
step3. 查看该键当前的值
step4. 再开一个
redis-cli
客户端,在该客户端中修改counter
的值
step5. 回到原始的
redis-cli
,开启一个事务并尝试递增counter
由于counter
在你开始事务之前已经被修改,所以EXEC
返回nil
,表示事务没有执行.
5.2.5 Redis持久化与事务持久性
Redis会把数据缓存在内存中,这在带来性能便利的同时,会给事务的持久性带来一定的障碍.事务的持久性是指,一旦Redis的事务通过EXEC
命令执行完成后,对Redis数据库的影响应当是永久性的.不过假设某事务执行后Redis服务器因断电重启,那么保存在该服务器内存里的Redis数据就会丢失,所以在这种场景里出现故障时无法确保事务的持久性
对此,可以通过Redis的持久化来确保事务的持久性.Redis持久化是指把Redis缓存数据从内存中保存到硬盘上.Redis持久化的方式有两种:
AOF:Append Only File(AOF)
RDB:Redis DataBase(RDB)
在后继章节里会详细讲述这两种能确保事务持久性的方式,这里仅给出实现AOF和RDB持久化的基本配置,以此来讨论这两种持久化与事务持久性的关系
AOF持久化方式能确保事务的持久性,而RDB方式则不能.
设置Redis服务器基于AOF的持久化:
AOF持久化的方式,针对Redis数据的事务能即时存入硬盘文件中.这样一旦出现故障,数据也不会丢失,由此能确保事务的持久性
设置Redis服务器基于RDB的持久化:
CONFIG SET dir
:设置待持久化文件的路径CONFIG SET dbfilename
:设置持久化文件的文件名
基于RDB的持久化方式是需要满足一定条件后(例如1分钟内至少有100个键被修改)才会触发持久性,反之不触发
所以,在某些场合里无法即时把Redis的修改记录到硬盘上,如果此时发生故障,数据就无法恢复,也就是说,Redis的RDB持久化方式无法确保事务的持久性
Last updated