事务是数据库管理系统执行过程中的一个逻辑单位,由一个有限的数据库操作序列构成。
为了说明情况在相对应的命令后面加了解释。
127.0.0.1:6379> MULTI // 开启事务
OK
127.0.0.1:6379> set k1 v1
QUEUED // QUEUED 表示入队
127.0.0.1:6379> get k1
QUEUED
127.0.0.1:6379> set k2 v2
QUEUED
127.0.0.1:6379> EXEC // 执行事务
1) OK
2) "v1"
3) OK
127.0.0.1:6379> FLUSHDB // 清空数据
OK
127.0.0.1:6379> MULTI // 开启事务
OK
127.0.0.1:6379> set k1 v1
QUEUED
127.0.0.1:6379> DISCARD // 取消事务
OK
127.0.0.1:6379> get k1
(nil)
127.0.0.1:6379> FLUSHDB // 清空数据
OK
127.0.0.1:6379> MULTI // 开启事务
OK
127.0.0.1:6379> set k1 v1
QUEUED
127.0.0.1:6379> set k2 v2
QUEUED
127.0.0.1:6379> set k3 // 模拟出错
(error) ERR wrong number of arguments for 'set' command
127.0.0.1:6379> EXEC // 执行事务
(error) EXECABORT Transaction discarded because of previous errors. // 事务因为前面的错误被取消
127.0.0.1:6379> get k1
(nil)
127.0.0.1:6379> keys *
(empty list or set)
注:如果执行的命令本身语法出错 (在事务中出错),那么这个事务中的所有命令都不会执行。
127.0.0.1:6379> FLUSHDB // 清空数据
OK
127.0.0.1:6379> MULTI // 开启事务
OK
127.0.0.1:6379> set k1 v1
QUEUED
127.0.0.1:6379> set k2 v2
QUEUED
127.0.0.1:6379> INCR k1 // 使 k1 自增 1
QUEUED
127.0.0.1:6379> EXEC // 执行事务
1) OK
2) OK // 前两条命令正确执行
3) (error) ERR value is not an integer or out of range // 由于 v1 是 String 类型不能自增,第三条命令报错
127.0.0.1:6379> mget k1 k2
1) "v1"
2) "v2"
注:如果在事务执行时出错 (在事务中不出错),那么只有出错的命令不执行,其他正确的命令会被执行。
Redis 与传统的关系型数据库事务最大的区别在于,Redis 不支持事务回滚机制。
Redis 的作者在事务功能文档中解释道:不支持复杂的事务回滚机制是因为与 Redis 追求的简单高效主旨不符,并且他认为事务执行出错往往都是编程错误导致的,所以他认为没有必要为 Redis 设计事务回滚功能。
正确执行:
127.0.0.1:6379> FLUSHDB // 清空数据
OK
127.0.0.1:6379> set money 100 // 初始化 money 为 100
OK
127.0.0.1:6379> WATCH money // 监视 money
OK
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> DECRBY money 10 // 将 money 减少 10
QUEUED
127.0.0.1:6379> EXEC // 执行事务,money 变为 90
1) (integer) 90
127.0.0.1:6379> get money
"90"
出错:
127.0.0.1:6379> WATCH money // 监视 money ,此时 money 为 90
OK
127.0.0.1:6379> DECRBY money 10 // 在事务开始之前将 money 减少 10,money 为 80
(integer) 80
127.0.0.1:6379> get money
"80"
127.0.0.1:6379> MULTI // 开启事务
OK
127.0.0.1:6379> DECRBY money 10 // 在事务中将 money 减少 10
QUEUED
127.0.0.1:6379> EXEC // 执行事务,没有命令被执行
(nil)
127.0.0.1:6379> get money // 查看 money 仍然为 80
"80"
注:在对一个 (或几个) key 进行监视之后,如果这个 (或者几个) key 的值在事务开启之前发生变化,那么在事务中操作这个 (几个)key 的命令将会被打断,有点类似乐观锁的作用。
127.0.0.1:6379> WATCH money // 监视 money 当前 money 为 80
OK
127.0.0.1:6379> UNWATCH // 取消对所有 key 的监视
OK
127.0.0.1:6379> DECRBY money 10 // 在事务执行之前将 money 减少 10 ,当前执行完 money 为 70
(integer) 70
127.0.0.1:6379> get money
"70"
127.0.0.1:6379> MULTI // 开启事务
OK
127.0.0.1:6379> DECRBY money 10 // 将 money 减少 10
QUEUED
127.0.0.1:6379> EXEC // 执行事务,命令被正确执行
1) (integer) 60
127.0.0.1:6379> get money // money 被改为了 60
"60"
注:在对 key 进行监视之后,如果想要在事务开启之前操作被监视的 key ,那么可以通过 UNWATCH 取消对所有 key 的监控。
- 开始:以 MULTI 开始一个事务
- 入队:将多个命令入队到事务中,接到这些命令并不会立即执行,而是放到等待执行的事务队列里面
- 执行:由 EXEC 命令触发事务
- 原子性:Redis 具备原子性,但是命令执行出错后不支持事务回滚
- 一致性:Redis 具备一致性
- 隔离性:Redis 采用单线程执行,因此事务总是以串行的方式执行,因此 Redis 也是具备隔离性的
- 持久性:Redis 的持久性意味着执行事务产生的结果被永久性的保存到硬盘里,即使服务器宕机,数据也不应该丢失,因此 Redis 的持久性由 Redis 的持久化方案决定。当服务器在 AOF 持久化模型下,当 appendfync 配置为 always 时,Redis 的事务也具备持久性