事务

原创 2016年05月30日 13:03:46
事务:提供一种将多个命令请求打包,然后一次性、按顺序地执行多个命令的机制,并且在事务执行期间,服务器不会中断事务而改去执行其他客户端的命令请求,它将事务中的所有命令都执行完毕,然后才会处理其他客户端的命令请求。

1. 事务的实现

三个阶段:

1.1 MULTI命令:事务的开始

执行该命令的客户端从非事务状态切换至事务状态,在客户端状态的flags属性中打开REDIS_MULTI标识完成.

127.0.0.1:6379> MULTI
OK

1.2 命令入队(事务队列)

127.0.0.1:6379> SET name "xiaoming"
QUEUED
127.0.0.1:6379> GET name
QUEUED
127.0.0.1:6379> SET author "peter"
QUEUED
127.0.0.1:6379> GET author
QUEUED

这里写图片描述

typedef struct redisClient{
    //...

    //事务状态
    multiState mstate;

    //...
};
typedef struct mltiState{
    //事务队列,FIFO顺序
    multiCmd *commands;  //数组,存放命令
    //已入队命令计数
    int count;
};
typedef struct multiCmd{
    //参数
    robj **argv;

    //参数数量
    int argc;

    //命令指针
    struct redisCommand *cmd;
};

事务队列的实现:

这里写图片描述

1.3 执行事务

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

127.0.0.1:6379> EXEC
1) OK
2) "xiaoming"
3) OK
4) "peter"
127.0.0.1:6379> 

2. WATCH 命令的实现

WATCH命令是一个乐观锁,在EXEC命令执行前,监视热议数量的数据库键,并在EXEC命令执行时,检查被监视的键是否至少有一个已经被修改过了,如果是的话,服务器将拒绝执行事务,并向客户端代表事务执行失败的空回复。

2.1 使用WATCH命令监视数据库键

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

typedef struct redisDb{

    //...

    //正在被WATCH命令监视的键
    dict *watched_keys;

    //...

}redisDb;

这里写图片描述

//监视name键和age键
redis> WATCH "name" "age"
OK

2.2 监视机制的触发

所有对数据库进行修改的命令(SET/LPUSH/SADD/ZREM/DEL/FLUSHDB等),在执行后都会调用 multi.c/touchWatchedKey函数对watched_keys字典进行检查,如果有客户端监视,会将监视被修改的客户端的REDIS_DIRTY_CAS标识打开,表示该客户端的事务安全性被破坏。

/* "Touch" a key, so that if this key is being WATCHed by some client the
 * next EXEC will fail. 
 *
 * “触碰”一个键,如果这个键正在被某个/某些客户端监视着,
 * 那么这个/这些客户端在执行 EXEC 时事务将失败。
 */
void touchWatchedKey(redisDb *db, robj *key) {
    list *clients;
    listIter li;
    listNode *ln;

    // 字典为空,没有任何键被监视
    if (dictSize(db->watched_keys) == 0) return;

    // 获取所有监视这个键的客户端
    clients = dictFetchValue(db->watched_keys, key);
    if (!clients) return;

    /* Mark all the clients watching this key as REDIS_DIRTY_CAS */
    /* Check if we are already watching for this key */
    // 遍历所有客户端,打开他们的 REDIS_DIRTY_CAS 标识
    listRewind(clients,&li);
    while((ln = listNext(&li))) {
        redisClient *c = listNodeValue(ln);

        c->flags |= REDIS_DIRTY_CAS;
    }
}

2.3 判断失误是否安全

这里写图片描述

2.4 一个完整的WATCH事务执行过程

(1)监视

c10086> WATCH "name"  //将客户端c10086添加到db[i]->watched_keys[name]的链表中。
OK

(2)创建事务

c10086> MULTI
OK

c10086> SET "name" "peter"
QUEUED

(3)这时另一个客户端修改了”name“键

c999> SET "name" "john"
OK

(4)当c10086再执行EXEC时,已经是事务安全性破坏。服务器拒绝它提交的事务

c10086> EXEC
(nil)

3. 事务的ACID性质

事务总是具有四个性质:

  • 原子性(Atomicity)
  • 一致性(Consistency)
  • 隔离性(Isolation)
  • 耐久性(Durability)

3.1 原子性

事务的原子性:事务中的多个操作当作一个整体来执行,服务器要么执行事务中的所有操作,要么一个操作也不执行。

3.2 一致性

数据库在执行事务之前是一致的,那么在执行事务后,无论事务是否执行成功,数据库也仍是一致的。
”一致“指的是数据符合数据库本身的定义和要求,没有包含非法或者无效的错误数据。

3.3 隔离性

事务的隔离性:即使数据库中有多个事务并发地执行,各个事务之间也不会互相影响,并且在并发状态下执行的事务和串行状态下执行的事务产生的结果完全相同。(有点类似于并发安全性)

3.4 耐久性

事务的耐久性:当事务执行完毕时,结果已经保存到永久性存储介质了。

版权声明:本文为博主原创文章,未经博主允许不得转载。

什么是嵌套事务?

什么是嵌套事务? 嵌套事务是一个外部事务的一个子事务,是一个外部事务的一个组成部分,当嵌套事务发生异常,而回滚,则会回复到嵌套事务的执行前的状态,相当于嵌套事务未执行。 如果外部事务回滚...
  • u014698348
  • u014698348
  • 2016年11月12日 18:54
  • 1335

PHP中实现MySQL嵌套事务的两种解决方案

一、问题起源 在MySQL的官方文档中有明确的说明不支持嵌套事务: 1. Transactions cannot be nested. This is a consequence of the i...
  • hello_katty
  • hello_katty
  • 2015年04月23日 13:52
  • 2473

数据库中事务是什么意思?

什么是事务?我们知道,数据库是一个面向多用户的共享机制,因此数据库管理系统应当具备并发控制和封锁机制,保证数据库系统的正常运行。但是当多个用户访问数据库的时候,如果每一个用户程序一个一个的串行执行,则...
  • u014180714
  • u014180714
  • 2014年09月14日 22:12
  • 4502

MySQL与Spring事务管理

数据库事务是保证在并发情况下能够正确执行的重要支撑,MySQL常见的数据库引擎中支持事务的是InnoDB,事务就是一系列操作,正确执行并提交,如果中途出现错误就回滚。事务要保证能够正常的执行,就必须要...
  • micro_hz
  • micro_hz
  • 2017年03月02日 20:08
  • 678

事务声明声明式事务和编程式事务介绍

编程式事务:所谓编程式事务指的是通过编码方式实现事务,即类似于JDBC编程实现事务管理。管理使用TransactionTemplate或者直接使用底层的PlatformTransactionManag...
  • u013083576
  • u013083576
  • 2016年06月24日 17:41
  • 7190

全局事务和局部事务

对于事务管理,J2EE开发者有两种选择:全局事务和局部事务。 1、全局事务        全局事务由应用服务器通过JTA进行管理。以前,使用全局事务比较流行的方法是采用EJB CMT,CMT是声明...
  • xiaoguang0904
  • xiaoguang0904
  • 2014年10月31日 14:31
  • 564

Redis事务介绍(四)

前言: 在传统的关系型数据库中,我们都知道有事务这么个东东存在,所谓的事务也就是应用程序中一系列严密的操作,所有操作必须成功完成,否则在每个操作中所作的所有更改都会被撤消,也就是事务具有原子性,一个...
  • cuipeng0916
  • cuipeng0916
  • 2016年12月16日 23:02
  • 687

事务的状态(状态模式)

【0】README 0.1)本文部分文字描述转自 “head first设计模式”,旨在学习  事务的状态(状态模式) 的基础知识; 【1】应用场景一 1.1)还记得成都市各大高校内的米源自动售卖...
  • PacosonSWJTU
  • PacosonSWJTU
  • 2016年03月26日 13:16
  • 655

Sqlite事务理解

大家在使用sqlite的时候应该都知道每一条操作都是通过一个SQL语句来完成的,例如: SQLiteDatabase db = ...; db.execSQL("insert into person...
  • chuwe1
  • chuwe1
  • 2016年06月02日 09:47
  • 1259

mysql之事务详解

我们知道,应用中的一个业务逻辑,往往由多条语句组合完成。那么我们就可以简单地将事务理解为一组SQL语句的集合,要么这个集合全部成功集合,要么这个集合就全部失败退回到第一句之前的状态。语法我们先来看看事...
  • mevicky
  • mevicky
  • 2015年12月16日 21:28
  • 4163
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:事务
举报原因:
原因补充:

(最多只允许输入30个字)