Redis事务详解

Redis作为一个数据库,也有事务的概念,本文就从事务的四大特性来分析以下Redis的事务。

1、原子性

原子性是事务的一个非常重要的特性。就是一个事务中的操作要么全部执行,要么全部不执行。

Redis中提供了与原子性有关的命令:
MUlTI:
用于显示开启一个事务,之后的操作都不会立即执行,而是进入一个操作队列

EXEC
依次执行操作队列中的所有操作。

DISCARD
抛弃操作队列中的所有操作,也就是所有操作都不执行

事务执行过程
1、事务开启
通过MULTI命令来显示开启事务

2、命令入队
客户端所有的命令都会被加入一个队列,并不会被立即执行

3、执行事务
通过EXEC将依次执行命令队列中的所有命令

multi
set name jaychou
getname
exec

Redis事务详解

multi
set name jay
getname
discard

Redis事务详解
出错
当命令中出现语法错误的时候,命令队列中所有命令都不会执行
Redis事务详解

但是当命令中出现语义错误的时候,命令队列中的其他正确指令都会执行,这就不满足原子性了。
Redis事务详解
Watch

当事务开启前可以使用watch命令,watch 的 用法是 watch key1,key2,事务会监视着key1和key2.

当开启事务后,如果对应的key被其他事务修改了,那么当前事务如果再修改对应的key就是失败,命令队列中的所有命令都不会执行。

这是一种乐观锁做法,跟CAS是一个思想。

Watch适用于并发操作,比如银行卡转账等操作。redis的是单线程运行的,虽然不会造成数据的不一致,但是会造成数据的过界现象。

我们以账户余额为例,
两个账户同时执行下面的这两行代码

get balance
decrby balance 10

假如balance的初值是10.也就是账户里只有10块钱。

如果两个客户端先后执行了get balance,发现账户里还有10块钱,就都开始扣10块钱。

两个decrby balance 10先后执行,这时会发现 balance变成了-10,这是不允许的。。。

所以可以通过watch来监视balance这个key,这样的话,当一个key发生变化的时候,事务不会执行

get balance
watch balance
multi
decrby balance 10
exec

Watch的内部实现

我们首先看下redisDb的内部结构

typedef struct redisDb {
    dict *dict;                
    dict *expires;             
    dict *blocking_keys;        
    dict *ready_keys;       
    //这里这里这里    
    dict *watched_keys;         /* WATCHED keys for MULTI/EXEC CAS */
    int id;                     /* Database ID */
} redisDb;

其中有一个名字叫watched_keys的dict,watch_keys中存放的是key和其对应的watch监视的客户端链表。
Redis事务详解

当一个客户端执行exec,想要改变某个key的时候,会首先查看其REDIS_DIRTY_CAS选项是否被打开,如果打开了,说明有其他事务打开了,事务就不会执行。

如果REDIS_DIRTY_CAS选项没有被打开,就可以执行对应的key,并且通过watched_keys获取key对应的监视列表,然后依次将对应客户端的REDIS_DIRTY_CAS选项打开。

当其他客户端发起exec的时候,发现自己的REDIS_DIRTY_CAS被打开了,就会停止事务运行。

当事务调用了exec后,无论事务执行成功还是失败,对应的监视都会被取消,对应的REDIS_DIRTY_CAS也会被关闭。

可以使用unwatch命令来手动关闭所有key的监视。

总结来看,redis并不满足原子性,当发生语义错误或者掉电的时候,事务是不会回滚的。

2、隔离性

因为Redis是单线程来处理请求的,所以事物之间是天然隔离的。

3、一致性

一致性指的是随着事务的执行完毕,数据库必须从一个正确的状态跳转到另一个正确的状态。这一个一致性就需要用户或者系统的定义,比如转账的操作就是所有账户的总额必须保持不变。也就说在转账事务执行完毕后,所有账户的总额必须保持不变,这就是保持了数据库的一致。

但是Redis当发生语义错误或者掉电的时候,事务是不会回滚的,比如转账扣除了A的账户金额,但是这时系统掉电了,而且Redis也不会回滚事务,这就造成了账户金额减少了,不一致了。

所以Redis是不一致的。

4、持久性

Redis可以通过RDB和AOF来将内存中数据保存到硬盘中,满足持久化。

上一篇:CF1598F - RBS (状压dp)


下一篇:202104-2 邻域均值