Redis|事务

102 阅读4分钟

Redis事务

Redis事务的概念

Redis 事务的本质是一组命令的集合。事务支持一次执行多个命令,一个事务中所有命令都会被序列化。在事务执行过程,会按照顺序串行化执行队列中的命令,其他客户端提交的命令请求不会插入到事务执行命令序列中

事务实现

Redis使用MULTIDISCARD , WATCHUNWATCH 命令来实现事务功能。

  • 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 返回一个应答数组,数组中的每个元素对应着事务中的一个命令,和命令发送的顺序一致

事务内部错误

事务可能会遇到两种类型的命令错误:

  • 在调用 EXEC 之前出错,命令加入队列失败。例如,命令的参数个数不符,或者内存补足。
  • 命令可能在执行 EXEC 之后失败,例如,对错误值类型的key执行操作(像在字符串值上执行列表操作)。

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)正常执行

image.png

(2)放弃事务

image.png

(3)若在事务队列中存在命令性错误(类似于java编译性错误),则执行EXEC命令时,所有命令都不会执行

image.png

(4)若在事务队列中存在语法性错误(类似于java的1/0的运行时异常),则执行EXEC命令时,其他正确命令会被执行,错误命令抛出异常。

image.png

(5)使用watch
案例一:使用watch检测balance,事务期间balance数据未变动,事务执行成功

image.png

案例二:使用watch检测balance,在开启事务后(标注1处),在新窗口执行标注2中的操作,更改balance的值,模拟其他客户端在事务执行期间更改watch监控的数据,然后再执行标注1后命令,执行EXEC后,事务未成功执行。

image.png

image.png