Redis事务详解

x33g5p2x  于11个月前 转载在 Redis  
字(1.8k)|赞(0)|评价(0)|浏览(83)

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

1、原子性

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

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

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

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

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

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

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

multi
set name jaychou
getname
exec

multi
set name jay
getname
discard

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

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

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监视的客户端链表。

当一个客户端执行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来将内存中数据保存到硬盘中,满足持久化。

相关文章

热门文章

更多