Redis事务
Redis事务的概念
Redis 事务的本质是一组命令的集合。事务支持一次执行多个命令,一个事务中所有命令都会被序列化。在事务执行过程,会按照顺序串行化执行队列中的命令,其他客户端提交的命令请求不会插入到事务执行命令序列中
事务实现
Redis使用MULTI, DISCARD , WATCH 和 UNWATCH 命令来实现事务功能。
- WATCH key1 key2 ... : 监视一或多个key,如果在事务执行之前,被监视的key被其他命令改动,则事务被打断 ( 类似乐观锁 )
- MULTI: 标记一个事务块的开始( queued )
- EXEC: 执行所有事务块的命令 ( 一旦执行exec后,之前加的监控锁都会被取消掉 )
- DISCARD: 取消事务,放弃事务块中的所有命令
- UNWATCH: 取消watch对所有key的监控
命令示范
(1)事务开始MULTI
> MULTI
OK
(2)命令入队
> INCR foo
QUEUED
> INCR bar
QUEUED
(3)执行事务 EXEC
> EXEC
1) (integer) 1
2) (integer) 1
EXEC 返回一个应答数组,数组中的每个元素对应着事务中的一个命令,和命令发送的顺序一致
事务内部错误
事务可能会遇到两种类型的命令错误:
Redis事务中的命令允许失败,但是Redis会继续执行其它的命令而不是回滚所有命令。 这么做的原因有两点:
(1) Redis 命令只在两种情况失败;
- 语法错误的时候才失败(在命令输入的时候不检查语法)
- 要执行的key数据类型不匹配:这种错误实际上是编程错误,这应该在开发阶段被测试出来,而不是生产上
(2)因为不需要回滚,所以Redis内部实现简单并高效。
WATCH命令
WATCH是一个乐观锁,在EXEC命令执行之前,监视任意数量的数据库键; EXEC命令执行时,检测被监视键是否被修改,如果是服务器拒绝执行事务
ACID性质
A 原子性
redis的事务队列中的命令要么全部执行,要么不都不执行,因此具有原子性;
redis不支持事务回滚机制
C 一致性
如果一个事务的指令全部被执行,那么数据库的状态是满足数据库完整性约束的。
分析redis执行可能出错的情况:
- 入队错误,命令不存在或格式不正确等,redis拒绝执行
- 执行错误, 出错的命令会被识别,不会对数据库进行修改,不会对一致性产生影响
- 服务器停机,不会影响一致性
综上,redis事务满足一致性约束
I 隔离性
redis 单线程执行事务(以及事务队列中的命令),服务器保证执行期间不会对事务进行中断, 因此,事务总是串行运行,总是具有隔离性
D 耐久性
redis并没有为事务提供额外的持久化功能,耐久性由redis持久化模式决定
AOF持久化模式下,并且appendfsync 选项的值为always,具有耐久性
Redis事务使用案例
(1)正常执行
(2)放弃事务
(3)若在事务队列中存在命令性错误(类似于java编译性错误),则执行EXEC命令时,所有命令都不会执行
(4)若在事务队列中存在语法性错误(类似于java的1/0的运行时异常),则执行EXEC命令时,其他正确命令会被执行,错误命令抛出异常。
(5)使用watch
案例一:使用watch检测balance,事务期间balance数据未变动,事务执行成功
案例二:使用watch检测balance,在开启事务后(标注1处),在新窗口执行标注2中的操作,更改balance的值,模拟其他客户端在事务执行期间更改watch监控的数据,然后再执行标注1后命令,执行EXEC后,事务未成功执行。