文章开始啰嗦两句,写到这里共21篇关于redis的琐碎知识,没有过多的写编程过程中redis的应用,着重写的是redis命令、客户端、服务器以及生产环境搭建用到的主从、哨兵、集群实现原理,如果你真的能看的进去,相信对你在以后用到redis时会有一定的帮助。

写到现在,redis相关的内容暂时告一段落了,以后可能更着重的去介绍c#相关的知识,包括用到IL、.net core底层、微服务等知识。

哎呀,写着写着突然又想啰嗦几句,最近几年c#在国内式微java如日中天,好多微软系的小伙伴或者各路大神都不看好c#,网上相关的帖子更是多如牛毛,另外一个现象就是从职位到薪资被java、go等语言甩了n条街。

但我觉得抛开这些外界因素,单从技术或者说是语言上讲c#其实非常优秀,虽然近几年.net  core 有些不伦不类、各种借鉴(抄袭)其他语言的语法糖、各个大版本之间不兼容等问题一堆,但是这并不影响他的优秀,毕竟成长确实要走很多弯路,所以希望有兴趣继续搞搞.net 的童鞋可以持续关注c#。


Redis通过MULTI、EXEC、WATCH等命令来实现事务,事务提供了一种将多个命令请求打包,然后一次性、按顺序地执行多个命令的机制,并且在事务执行期间,服务器不会中断事务而改去执行其他客户端命令请求,他会将事务中的所有命令执行完毕,然后采取处理其他客户端的命令请求。

一个事务从开始到结束通常会经历以下三个阶段:事务开始、命令入队、事务执行。

1)事务开始

MULTI命令的执行标志是事务的开始,MULTI命令可以将执行该命令的客户端的从非事务状态切换至事务状态,这一切是通过在客户端状态的flags属性中打开REDIS_MULTI标识来完成的。

2)命令入队

如果客户端发送的命令为EXEC、DISCARD、WATCH、MULTI四个命令的其中一个,那么服务器立即执行这个命令,相反,服务器并不会立即执行这个命令,而是将命令放入到一个事务队列中,而后向客户端返回QUEUED回复。

每个Redis客户端都有自己的事务状态,这个事务状态保存在客户端状态的mstate属性里面:

typedef struct redisClient{
//事务状态
multiState mstate;
} redisClient;

事务状态包含一个事务队列,以及一个已入队命令的计数器:

typedef struct multiState{
//事务队列,FIFO顺序
multiCmd *commands;
///已入队列计数
int count;
} multiState;
typedef struct multiCmd{
//参数
robj **argv;
//参数数量
int argc;
//命令指针
struct redisCommand *cmd;
} multiCmd;

事务队列以先进先出的方式 保存入队的命令。

3)执行事务

当一个处于事务状态的客户端向服务器发送EXEC命令时,这个EXEC命令将立即被服务器执行。服务器会遍历这个客户端的事务队列,执行队列中保存的所有命令,最后将执行命令所得的结果全部返回给客户端。

WATCH命令

watch命令是一个乐观锁,它可以在exec命令执行之前,监视任意数量的数据库键,并在EXEC命令执行时,检查被监视的键是否至少有一个已经被修改过,如果是的话,服务器将拒绝执行事务,并向客户端返回标识事务执行失败的空回复。

每个Redis数据库都保存着一个watched_keys字典,这个键是某个被watch命令监视的数据数据库键,而字典的值是一个链表,链表中记录了所有被监视相应数据库键的客户端。

typedef struct redisDb{
//正在被watch命令监视的键
dict *watched_keys;
} redisDb;

监视机制的触发:所有对数据库进行修改的命令,在执行之后都会调用touchWatchKey函数对watched_keys字典进行检查,查看是否在客户端正在监视刚刚被命令修改过的数据库键,如果有的话,那么touchWatchKey函数会将监视被修改键的客户端的REDIS_DIRTY_CAS标识打开,标识该客户端的事务安全性已经被破坏。

判断事务是否安全

当服务器接收到一个客户端发来的EXEC命令时,服务器会根据客户端是否打开REDIS_DIRTY_CAS标识来决定是否执行事务:如果客户端的REDIS_DIRTY_CAS标识已经被打开,那么说明客户端所监视的键当中,至少有一个键已经被修改过了,在这种情况下,客户端提交的事务已经不再安全,所以服务器会拒绝执行客户端提交的事务;如果客户端REDIS_DIRTY_CAS标识没有被打开,那么说明客户端监视的所有键都没有被修改过,事务仍然是安全的,服务器将执行客户端提交的这个事务。

事务的ACID性质

原子性:Redis的事务和传统的关系型数据库事务最大的区别在于,Redis不支持事务回滚机制,事务队列中的某个命令在执行期间出现错误,整个事务也会继续执行下去,直到将事务队列中的所有命令都执行完毕为止。

一致性:

1、入队错误,如果一个事务在入队命令的过程中,出现了命令不存在,或者命令的格式不正确的情况那么Redis将拒绝执行这个事务

2、执行错误:执行过程中发生的错误都是一些不能再入队时被服务器发现的错误,这些错误只会在命令实际执行时被触发;即使在事务的执行过程中发生了错误,服务器也不会中断事务的执行,他会继续执行事务中余下的其他命令,并且一致性的命令不会被出错的命令影响。

3、服务器停机:如果服务器运行在无持久化的内存模式中,那么重启之后数据库将是一片空白的,因此数据总是一致性的;如果服务器运行了RDB模式下,那么事务中途停机不会导致不一致性,因为服务器可以根据现有的RDB文件来恢复数据,从而将数据库还原到一个一致性的状态。如果服务器运行在APF模式下,那么事务中途停机不会导致不一致性,因为服务器可以根据现有的APF文件来恢复数据,从而将数据库还原至一致的状态。

隔离性:Redis使用单线程的方式执行事务,并且服务器保证,在执行事务期间不会对事务中断,因此,redis的事务总是以串行的方式运行,并且事务也总是具有隔离性的。

耐久性:Redis事务的耐久性由Redis所使用的持久化模式决定的,(不论Redis在什么模式下运行,在一个事务的最后加上SAVE命令总可以保证事务的耐久性。)


每天学一点,总会有收获。

说明:尊重作者知识产权,文中内容参考《Redis设计与实现》,仅在此做学习与大家分享。


Redis学习笔记(二十一) 事务的更多相关文章

  1. Redis学习笔记二 (BitMap算法分析与BitCount语法)

    Redis学习笔记二 一.BitMap是什么 就是通过一个bit位来表示某个元素对应的值或者状态,其中的key就是对应元素本身.我们知道8个bit可以组成一个Byte,所以bitmap本身会极大的节省 ...

  2. python3.4学习笔记(二十一) python实现指定字符串补全空格、前面填充0的方法

    python3.4学习笔记(二十一) python实现指定字符串补全空格.前面填充0的方法 Python zfill()方法返回指定长度的字符串,原字符串右对齐,前面填充0.zfill()方法语法:s ...

  3. (C/C++学习笔记) 二十一. 异常处理

    二十一. 异常处理 ● 异常的概念 程序的错误通常包括:语法错误.逻辑错误.运行异常. 语法错误指书写的程序语句不合乎编译器的语法规则,这种错误在编译.连接时由编译器指出. 逻辑错误是指程序能顺利运行 ...

  4. redis学习笔记 - Pipeline与事务

    原文 Redis提供了5种数据结构,但除此之外,Redis还提供了注入慢查询分析,Redis Shell.Pipeline.事务.与Lua脚本.Bitmaps.HyperLogLog.PubSub.G ...

  5. Redis学习笔记(十一) 服务器

    Redis服务器负责与多个客户端建立网络通信,处理客户端发送的命令请求,在数据库中保存客户端执行命令所产生的数据,并通过资源管理来维持服务器自身的运转. 命令请求过程 以set命令为例 1.客户端向服 ...

  6. Redis学习笔记二

    学习Redis添加Object时,由于Redis只能存取字符串String,对于其它数据类型形容:Int,long,double,Date等不提供支持,因而需要设计到对象的序列化和反序列化.java序 ...

  7. Redis学习笔记二:单机数据库的实现

    1. 数据库 服务器中的数据库 Redis服务器将所有数据库都保存在服务器状态redis.h/redisServer结构的db数组中,db数组的每个项都是一个redis.h/redisDb结构,每个r ...

  8. redis 学习笔记二 (简单动态字符串)

    redis的基本数据结构是动态数组 一.c语言动态数组 先看下一般的动态数组结构 struct MyData { int nLen; char data[0]; }; 这是个广泛使用的常见技巧,常用来 ...

  9. Java基础学习笔记二十一 多线程

    多线程介绍 学习多线程之前,我们先要了解几个关于多线程有关的概念.进程:进程指正在运行的程序.确切的来说,当一个程序进入内存运行,即变成一个进程,进程是处于运行过程中的程序,并且具有一定独立功能. 线 ...

  10. StackExchange.Redis学习笔记(二) Redis查询 五种数据类型的应用

    ConnectionMultiplexer ConnectionMultiplexer 是StackExchange.Redis的核心对象,用这个类的实例来进行Redis的一系列操作,对于一个整个应用 ...

随机推荐

  1. mysql运维入门1:基础及备份还原

    存储引擎 myisam 表强调的是性能 执行速度比innodb类型更快 不提供事务支持 如果执行大量的select操作,是首选 支持表锁,不支持行锁 innodb 提供事务支持.外键等高级数据库功能 ...

  2. INNODB 数据页结构

    InnoDB DataPage 16384B 16K 38B FILE HEADER 56B PAGE HEADER RECORD Infimum + supremum Records UserRec ...

  3. jquery.autocomplete的使用-----------------------摘抄别人的

    作者:lxhwss | 2011/10/11 9:46:38 | 阅读43次 document.write(”<script language=javascript src=’/js/2.js’ ...

  4. http://blog.itpub.net/28602568/viewspace-759789/

    varchar .varchar2.nvarchar.nvarchar2  -->存储可变的字符串 varchar .varchar2:varchar:汉字全角等字符占2字节,数字.字母均1个字 ...

  5. 王玉兰201771010128《面象对象程序设计(Java)》第九周学习总结

    第一部分:理论基础部分总结: 一:(1)异常:在程序的执行过程中所发生的异常事件,它中断指令的正常执行. 常见的几种错误:A:用户输入错误:B:设备错误;硬件出错:C:物理限制:磁盘满了,可用存储空间 ...

  6. 51Nod栈

    LYK有一个栈,众所周知的是这个数据结构的特性是后进先出的. LYK感觉这样子不太美妙,于是它决定在这个前提下将其改进,也就是说,每次插入元素时,可以在栈顶或者栈底插入,删除元素时,只能在栈顶删除.L ...

  7. hdu2243

    背单词,始终是复习英语的重要环节.在荒废了3年大学生涯后,Lele也终于要开始背单词了.一天,Lele在某本单词书上看到了一个根据词根来背单词的方法.比如"ab",放在单词前一般表 ...

  8. springboot使用Jwt处理跨域认证问题

    在前后端开发时为什么需要用户认证呢?原因是由于HTTP协定是不存储状态的,这意味着当我们透过账号密码验证一个使用者时,当下一个request请求时他就把刚刚的资料忘记了.于是我们的程序就不知道谁是谁了 ...

  9. windows环境下Kubernetes及Docker安装(那些坑)

    k8s 和 Docker容器技术,当前非常流行的技术. 让人日狗的是,   这套技术栈对CN的donet 程序员不怎么友好.娓娓道来,1. 好多镜像都是需要梯子才能访问: 2. window程序员天生 ...

  10. 【C++】常见易犯错误之数值类型取值溢出与截断(1)

    1. 数据类型数值范围溢出 如标题所述,该错误出现的原因是由于变量的值超出该数据类型取值范围而导致的错误. 例题如下: (IDE环境:C-Free,编译器为mingw5,如下图) # include ...