这篇我们插一段关于redis中事务的讨论。
相关的命令:
MULTI:事务的开始
EXEC:事务的执行
WATCH:监视数据库键
DISCARD:停止事务
源码在multi.c中
void multiCommand(redisClient *c) {
if (c->flags & REDIS_MULTI) {
addReplyError(c,"MULTI calls can not be nested");
return;
}
//打开事务标识
c->flags |= REDIS_MULTI;
addReply(c,shared.ok);
}
void execCommand(redisClient *c) {
int j;
robj **orig_argv;
int orig_argc;
struct redisCommand *orig_cmd;
int must_propagate = 0; /* Need to propagate MULTI/EXEC to AOF / slaves? */
if (!(c->flags & REDIS_MULTI)) {
addReplyError(c,"EXEC without MULTI");
return;
}
if (c->flags & (REDIS_DIRTY_CAS|REDIS_DIRTY_EXEC)) {
addReply(c, c->flags & REDIS_DIRTY_EXEC ? shared.execaborterr :
shared.nullmultibulk);
discardTransaction(c);
goto handle_monitor;
}
unwatchAllKeys(c); /* Unwatch ASAP otherwise we'll waste CPU cycles */
orig_argv = c->argv;
orig_argc = c->argc;
orig_cmd = c->cmd;
addReplyMultiBulkLen(c,c->mstate.count);
for (j = 0; j < c->mstate.count; j++) {
c->argc = c->mstate.commands[j].argc;
c->argv = c->mstate.commands[j].argv;
c->cmd = c->mstate.commands[j].cmd;
if (!must_propagate && !(c->cmd->flags & REDIS_CMD_READONLY)) {
execCommandPropagateMulti(c);
must_propagate = 1;
}
call(c,REDIS_CALL_FULL);
c->mstate.commands[j].argc = c->argc;
c->mstate.commands[j].argv = c->argv;
c->mstate.commands[j].cmd = c->cmd;
}
c->argv = orig_argv;
c->argc = orig_argc;
c->cmd = orig_cmd;
discardTransaction(c);
if (must_propagate) server.dirty++;
handle_monitor:
if (listLength(server.monitors) && !server.loading)
replicationFeedMonitors(c,server.monitors,c->db->id,c->argv,c->argc);
}
接下里我们用图来介绍一下执行流程:
复制代码
下面再讨论一下redis中出错的处理机制。
命令错误:整个事务无法执行
运行时错误:需要人工参与
复制代码
注:redis不支持回滚
redis中的乐观锁:watch
接下里再看看redis事务的ACID性质
原子性:见上面redis的出错处理机制
一致性:
服务器停机
无持久化的内存模式,OK
RDB模式,OK
AOF模式,OK
隔离性
耐久性:AOF模式下appendfsync值为always时,OK
一致性和耐久性和redis的持久化密切相关,之后涉及到再进行谈论。
说完事务,对redis的pipeline也在此处进行了解,对比一下:
由上面的请求也可以看出了两者最明显的区别是客户端发送请求的方式不一样,具体相关区别如下:
pipeline选择客户端缓冲,multi选择服务端缓冲;
请求次数的不一致,multi需要每个命令都发送一次给服务端,pipeline最后一次性发送给服务端,请求次数相对于multi减少
multi/exec可以保证原子性,而pipeline不保证原子性
pipeline需要客户端自己开发配合,而且命令数不能太多,multi是redis服务端支持的,不需要client做任何事情复制代码