本质

一组命令的集合,一次性执行,按顺序执行,排他性(不允许被其他人干扰)。

有原子性?

Redis单条命令有原子性,但是事务不保证原子性!!!和Mysql是不同的!!!

有隔离级别?

没有。
所有命令在事务中,并没有被直接执行,而是在发起执行命令的时候才执行。

  1. ----队列
  2. set
  3. set
  4. set
  5. ...
  6. ---执行

正常执行事务

  1. 开启事务(multi)
  2. 命令入队: 正常写命令即可
  3. 执行事务 (exec)

image.png

放弃事务

  1. 开启事务(multi);
  2. 命令入队:正常写命令即可
  3. 放弃事务(Discard)

image.png

编译型异常

当代码有问题,命令有错的时候,事务中的所有命令都不会被执行,因为编译都没通过。
如下,有一行命令没有通过编译,当执行exec时,所有的命令都不会被执行。
image.png

运行时异常

例如 1 / 0, 该错误在编译时无法检查出来,只有在运行时才会被发现。此时其他命令可以正常执行,错误命令抛出异常。因此事务没有原子性。如下,可以看到第一条命令报错了,但是后面的命令都正常执行了。

image.png

监控(watch)

悲观锁

很悲观,认为什么时候都会出问题,无论做什么都会加锁。例如你上厕所的时候,一定锁门,因为你总认为外边有人要冲进来,不锁门不行的。

悲观锁最大的问题是效率低下。

乐观锁

很乐观,认为什么时候都不会出现问题,所以不会上锁!更新数据的时候去判断一下,在此期间是否有人修改过这个数据。

Mysql中用Version来实现乐观锁。

  • 获取version
  • 更新的时候比较version

Redis监控测试

正常执行成功

image.png
在watch的过程中,money的数据没有发生变动,可以正常执行成功。

多线程修改值后,修改失败(当乐观锁来操作)

线程1:
image.png
此时线程1并未执行事务,线程2插入进来,修改了money值。

线程1执行exec来执行事务,因为加了watch,redis知道值被修改了,于是本次事务执行失败、
image.png

解决办法

  • 先unwatch来解锁
  • 重新watch money
  • 开启事务,重新入队,执行。

image.png