Reids-事务

127 阅读3分钟

Redis事务

简介

简介

  1. Redis事务简单来说,就是一组redis命令的集合,先将这些命令序列化并放到事务的队列中,在发起了exec执行事务的命令时,这些命令才被执行
  2. Redis事务没有隔离级别的概念
  3. Redis单条命令保证原子性,但是Redis事务不保证原子性。
  4. Redis事务执行后,该事务就消失了,但是事务中命令创建的数据还在~~~

Redis事务的执行过程

  1. 开启事务 --- multi
  2. 在事务中放入Redis命令
  3. 执行事务 ---- exec

Redis事务演示

简单事务

#开启事务
127.0.0.1:6379> multi   
OK
#在事务中放入的命令
127.0.0.1:6379(TX)> set k1 1  
QUEUED   #成功将命令放入事务
127.0.0.1:6379(TX)> set k2 2
QUEUED
127.0.0.1:6379(TX)> set k3 3
QUEUED
127.0.0.1:6379(TX)> get k3
QUEUED
127.0.0.1:6379(TX)> get k1
QUEUED  
#执行事务
127.0.0.1:6379(TX)> exec
#执行结果
1) OK
2) OK
3) OK
4) "3"
5) "1"

放弃事务

127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> set k1 1
QUEUED
127.0.0.1:6379(TX)> set k2 2
QUEUED
127.0.0.1:6379(TX)> set k3 3
QUEUED
127.0.0.1:6379(TX)> get k3
QUEUED
127.0.0.1:6379(TX)> discard # 放弃事务
OK
127.0.0.1:6379> get k1
(nil)
127.0.0.1:6379> get k2
(nil)
127.0.0.1:6379> get k3
(nil)

事务命令编译异常

  • 代码问题,所有命令都不会被执行。
127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> set k1 1
QUEUED
127.0.0.1:6379(TX)> set  k2
(error) ERR wrong number of arguments for 'set' command  # 放入队列的时候报错,但还是放入了队列,不影响其他命令继续放入队列
127.0.0.1:6379(TX)> get k3
QUEUED
127.0.0.1:6379(TX)> set k3 3
QUEUED
127.0.0.1:6379(TX)> exec
(error) EXECABORT Transaction discarded because of previous errors.   # 执行时提示编译异常
127.0.0.1:6379> get k1  #测试,事务中的命令失效
(nil)

事务命令运行异常

  • 语法问题,有问题的命令不被执行,其他命令不受影响
127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> set k1 a
QUEUED
127.0.0.1:6379(TX)> incr k1  #语法错误,incr自增,k1的值只能是数字
QUEUED 
127.0.0.1:6379(TX)> get k1
QUEUED
127.0.0.1:6379(TX)> set k2 2
QUEUED
127.0.0.1:6379(TX)> set k3 3
QUEUED
127.0.0.1:6379(TX)> get k2
QUEUED
127.0.0.1:6379(TX)> exec # 执行事务发现只有存在语法错误的命令没有被实现,其他命令照样执行。
1) OK
2) (error) ERR value is not an integer or out of range  
3) "a"
4) OK
5) OK
6) "2"

Redis事务乐观锁

  • 监控实现 watch
  • 获取watch
  • 更新时比较watch 直接实例演示

成功事务乐观锁

127.0.0.1:6379> set money 100 
OK
127.0.0.1:6379> set out 0
OK
127.0.0.1:6379> watch money #监控money
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> decrby money 50 取50,银行的money少50
QUEUED
127.0.0.1:6379(TX)> incrby out 50   手里现金多50
QUEUED
127.0.0.1:6379(TX)> exec
1) (integer) 50
2) (integer) 50

失败事务乐观锁

线程一:取20,取完后,还没有执行的时候被线程二插队

127.0.0.1:6379> set money 100
OK
127.0.0.1:6379> set out 0
OK
127.0.0.1:6379> watch money
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> decrby money 20
QUEUED
127.0.0.1:6379(TX)> incrby out 20
QUEUED

线程二插队:

127.0.0.1:6379> incrby money 500
(integer) 600
127.0.0.1:6379> decrby out 500
(integer) -500
127.0.0.1:6379> get money
"600"
127.0.0.1:6379> get out
"-500"

这时候,再去线程一执行事务,发现执行失败

127.0.0.1:6379(TX)> exec
(nil)

这时候如果我们要正确读取到money,我们就需要unwatch来解决

127.0.0.1:6379> unwatch  # 先解锁
OK
127.0.0.1:6379> watch money # 重新获取值,再次监听
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> decrby money 100
QUEUED
127.0.0.1:6379(TX)> incrby out 100
QUEUED
127.0.0.1:6379(TX)> exec #执行成功
1) (integer) 500
2) (integer) -400