和关系型数据库事务类似,redis事务也是用来一次性地执行多条命令。
使用起来也很简单,可以用 multi
开启一个事务,然后将多个命令入队到事务的队列中,最后由exec
命令触发事务,执行事务中的所有命令。
看一个简单的事务执行例子:
127.0.0.1:6379> multi
OK
127.0.0.1:6379> set name "hyy"
QUEUED
127.0.0.1:6379> set age 20
QUEUED
127.0.0.1:6379> incr age
QUEUED
127.0.0.1:6379> exec
1) OK
2) OK
3) (integer) 21
可以看到,在指令和操作数的数据类型等都正常的情况下,输入EXEC
后所有命令被执行成功。
Redis事务相关命令:
Redis 事务功能是通过 multi、exec、discard、watch、unwatch 五个原语实现的
给出结论:Redis 的事务并不是我们传统意义上理解的事务,我们都知道 单个 Redis 命令的执行是原子性的,但 Redis 没有在事务上增加任何维持原子性的机制,所以 Redis 事务的执行并不是原子性的。
ACID中原子性的定义:
原子性:一个事务(transaction)中的所有操作,要么全部完成,要么全部不完成,不会结束在中间某个环节。事务在执行过程中发生错误,会被恢复(Rollback)到事务开始前的状态,就像这个事务从来没有执行过一样。
如果要验证redis事务是否满足原子性,那么需要在redis事务执行发生异常的情况下进行,下面我们分两种不同类型的错误分别测试。
incr
后面没有添加参数,属于命令格式不对的语法错误,这时在命令入队时就会立刻检测出错误并提示error
。使用exec
执行事务,查看结果输出:
127.0.0.1:6379> exec (error) EXECABORT Transaction discarded because of previous errors.
在这种情况下,只要事务中的一条命令有语法错误,在执行exec
后就会直接返回错误,包括语法正确的命令在内的所有命令都不会被执行。
对此进行验证,看一下在事务中其他指令执行情况,查看set
命令的执行结果,全部为空,说明指令没有被执行。
127.0.0.1:6379> get name (nil) 127.0.0.1:6379> get age (nil)
此外,如果存在命令本身拼写错误、或输入了一个不存在的命令等情况,也属于语法错误的情况,执行事务时会直接报错。string
类型数据进行incr
自增操作:
127.0.0.1:6379> multi OK 127.0.0.1:6379> set name "hyy" QUEUED 127.0.0.1:6379> set age twenty QUEUED 127.0.0.1:6379> incr age QUEUED
redis一直到这里都没有提示存在错误,执行exec
看一下结果输出:
127.0.0.1:6379> exec 1) OK 2) OK 3) (error) ERR value is not an integer or out of range 4) (integer) 1
运行结果可以看到,虽然incr age
这条命令出现了错误,但是它前后的命令都正常执行了,再看一下这些key
对应的值,确实证明了其余指令都执行成功:
127.0.0.1:6379> get name hyy 127.0.0.1:6379> get age "eighteen"对上面的事务的运行结果进行一下分析:
通过分析我们知道了redis中的事务是不满足原子性的。
在运行错误的情况下,并没有提供类似数据库中的回滚功能。那么为什么redis不支持回滚呢,官方文档给出了说明,大意如下:
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。