Redis学习笔记(二十一) 事务
文章开始啰嗦两句,写到这里共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学习笔记(二十一) 事务的更多相关文章
- Redis学习笔记二 (BitMap算法分析与BitCount语法)
Redis学习笔记二 一.BitMap是什么 就是通过一个bit位来表示某个元素对应的值或者状态,其中的key就是对应元素本身.我们知道8个bit可以组成一个Byte,所以bitmap本身会极大的节省 ...
- python3.4学习笔记(二十一) python实现指定字符串补全空格、前面填充0的方法
python3.4学习笔记(二十一) python实现指定字符串补全空格.前面填充0的方法 Python zfill()方法返回指定长度的字符串,原字符串右对齐,前面填充0.zfill()方法语法:s ...
- (C/C++学习笔记) 二十一. 异常处理
二十一. 异常处理 ● 异常的概念 程序的错误通常包括:语法错误.逻辑错误.运行异常. 语法错误指书写的程序语句不合乎编译器的语法规则,这种错误在编译.连接时由编译器指出. 逻辑错误是指程序能顺利运行 ...
- redis学习笔记 - Pipeline与事务
原文 Redis提供了5种数据结构,但除此之外,Redis还提供了注入慢查询分析,Redis Shell.Pipeline.事务.与Lua脚本.Bitmaps.HyperLogLog.PubSub.G ...
- Redis学习笔记(十一) 服务器
Redis服务器负责与多个客户端建立网络通信,处理客户端发送的命令请求,在数据库中保存客户端执行命令所产生的数据,并通过资源管理来维持服务器自身的运转. 命令请求过程 以set命令为例 1.客户端向服 ...
- Redis学习笔记二
学习Redis添加Object时,由于Redis只能存取字符串String,对于其它数据类型形容:Int,long,double,Date等不提供支持,因而需要设计到对象的序列化和反序列化.java序 ...
- Redis学习笔记二:单机数据库的实现
1. 数据库 服务器中的数据库 Redis服务器将所有数据库都保存在服务器状态redis.h/redisServer结构的db数组中,db数组的每个项都是一个redis.h/redisDb结构,每个r ...
- redis 学习笔记二 (简单动态字符串)
redis的基本数据结构是动态数组 一.c语言动态数组 先看下一般的动态数组结构 struct MyData { int nLen; char data[0]; }; 这是个广泛使用的常见技巧,常用来 ...
- Java基础学习笔记二十一 多线程
多线程介绍 学习多线程之前,我们先要了解几个关于多线程有关的概念.进程:进程指正在运行的程序.确切的来说,当一个程序进入内存运行,即变成一个进程,进程是处于运行过程中的程序,并且具有一定独立功能. 线 ...
- StackExchange.Redis学习笔记(二) Redis查询 五种数据类型的应用
ConnectionMultiplexer ConnectionMultiplexer 是StackExchange.Redis的核心对象,用这个类的实例来进行Redis的一系列操作,对于一个整个应用 ...
随机推荐
- 利用js实现 禁用浏览器后退| 去除上一个历史记录链接
也是查找了好多资料才找到的,这种方式,可以消除 后退的所有动作.包括 键盘.鼠标手势等产生的后退动作. <script language="javascript"> / ...
- Gym101635K Blowing Candles
题目链接:http://codeforces.com/gym/101635 题目大意: 推荐一篇文章:https://blog.csdn.net/wang_heng199/article/detail ...
- A+B Coming(hdu1720)
思考:十六进制的输入->%x,定义时用int.要变成十进制输出,直接在输出时用->%d. #include<stdio.h> int main() { int A,B; cha ...
- 解决iframe重定向让父级页面跳转
原文:http://www.jb51.net/article/40583.htm 有内嵌iframe的页面,当session过期时,点击连接重定向后的跳转会在iframe中跳转,在登录页面中加入下面的 ...
- 【Leetcode】287. 寻找重复数(数组模拟链表的快慢指针法)
寻找重复数 根据题意,数组中的数字都在1~n之间,所以数字的范围是小于数组的范围的,数组的元素可以和数组的索引相联系. 例如:nums[0] = 1 即可以将nums[0]作为索引 通过nums[0] ...
- 微信小程序语音同步智能识别的实现案例
目录 一.背景 二.同声传译插件介绍 1. 微信小程序后台添加插件 2. 微信小程序启用插件 三.语音同步转换的前端实现 1.界面UI与操作 2.代码实现 四.后端SpringBoot实现语音文件上传 ...
- 【原创】Linux中断子系统(一)-中断控制器及驱动分析
背景 Read the fucking source code! --By 鲁迅 A picture is worth a thousand words. --By 高尔基 说明: Kernel版本: ...
- 当微信小程序遇到云开发,再加上一个类似 ColorUI 的模板,人人都能做小程序了
作为一个 Java 程序员,早就想尝试一把微信小程序,但是一直苦于没有想法,再加上做一个漂亮的页面实在不太擅长. 由于自己比较喜欢历史,经常看历史方面的书.在一次梳理中国现有的朝代时,突然想到,要是可 ...
- 曹工说Spring Boot源码(29)-- Spring 解决循环依赖为什么使用三级缓存,而不是二级缓存
写在前面的话 相关背景及资源: 曹工说Spring Boot源码(1)-- Bean Definition到底是什么,附spring思维导图分享 曹工说Spring Boot源码(2)-- Bean ...
- Linux (五) VIM编辑器
个人博客网:https://wushaopei.github.io/ (你想要这里多有) 1.简介 Linux系统环境下的一款非常重要的文本编辑工具,我们在Linux环境下几乎所有的文本文件 ...