【四】、Redis的事务transition

导读:本篇文章讲解 【四】、Redis的事务transition,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com

四、事务transition

Redis的单条命令是保证原子性的,但是Redis的事务不能保证原则性

Redis事务的本质:一组命令的集合
——————队列set set set get … 执行 ——————
事务中的每条命令都会被序列化,执行过程中按顺序执行,不允许其他命令进行干扰

  • 一致性
  • 顺序性
  • 排他性

1.Redis事务没有隔离级别的概念

2.Redis单挑命令是保证原子性的,但是事务不保证原子性

隔离级别的概念可以参照博客

1.Redis事务操作过程

  • 开启事务(multi)
  • 命令入队
  • 执行事务(exec)

所以事务中的命令在加入时都是没有被执行的,直到提交时才会开始执行并且一次性完成

开始事务(multi

127.0.0.1:6379> keys *
(empty array)
127.0.0.1:6379> multi //开启事务
OK
127.0.0.1:6379(TX)> set k1 v1 //命令入队
QUEUED
127.0.0.1:6379(TX)> set k2 v2
QUEUED
127.0.0.1:6379(TX)> get k1
QUEUED
127.0.0.1:6379(TX)> set k3 v3
QUEUED
127.0.0.1:6379(TX)> keys *
QUEUED
127.0.0.1:6379(TX)> exec //执行事务
1) OK
2) OK
3) "v1"
4) OK
5) 1) "k2"
   2) "k3"
   3) "k1"

取消事务(discurd

127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> set k1 v1
QUEUED
127.0.0.1:6379(TX)> set k2 v2
QUEUED
127.0.0.1:6379(TX)> DISCARD //放弃事务之后就退出了事务控制(该版本会有TX提示)
OK
127.0.0.1:6379> exec
(error) ERR EXEC without MULTI
127.0.0.1:6379> get k1
(nil)

事务错误

1.代码语法错误时(编译时异常)所有命令都不执行

127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> set k1 v1
QUEUED
127.0.0.1:6379(TX)> set k2 v2
QUEUED
127.0.0.1:6379(TX)> error k1 //这是一条语法错误的命令
(error) ERR unknown command `error`, with args beginning with: `k1`, //会报错但不影响后续命令的输入
127.0.0.1:6379(TX)> get k2
QUEUED
127.0.0.1:6379(TX)> exec
(error) EXECABORT Transaction discarded because of previous errors.//语法有错误执行会报错
127.0.0.1:6379> get k1
(nil)//当编译有问题时所有命令都不执行

2.代码逻辑错误(运行时异常)其他命令可以正常执行,所以事务不保证原子性

127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> set k1 v1
QUEUED
127.0.0.1:6379(TX)> set k2 v2
QUEUED
127.0.0.1:6379(TX)> INCR k1 //这条命令的逻辑有问题,k1不是integer类型无法自增1
QUEUED
127.0.0.1:6379(TX)> get k2
QUEUED
127.0.0.1:6379(TX)> exec
1) OK
2) OK
3) (error) ERR value is not an integer or out of range//运行时报错
4) "v2"
//虽然中间有一条命令时逻辑错误,但是后面的执行依旧能够正常的执行
//所以说Redis单条指令保证原子性,但Redis事务不能保证原子性

监控(watch)

1.悲观锁

  • 很悲观,认为什么时候都会出现问题,无论做什么都会加锁

2.乐观锁

  • 很乐观,认为什么时候都不会出现问题,所以不会上锁!更新数据的时候去判断一下,在此期间是否有人修改过这个数据
  • 首先要获取一开始version
  • 更新的时候要比较我当前的version和我之前获取到的version是否一致,如果一致则执行成功,不一致则说明在此期间有人修改过这个数据,则执行失败

使用watch key监控指定数据,相当于加乐观锁

one. 正常执行

127.0.0.1:6379> set money 100 //设置余额:100
OK
127.0.0.1:6379> set use 0//支出使用: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 20
QUEUED
127.0.0.1:6379(TX)> INCRBY use 20
QUEUED
127.0.0.1:6379(TX)> exec//监视值没有被中途修改,事务正常执行
1) (integer) 80
2) (integer) 20

two.异常执行

测试多线程修改值,使用watch可以当作redis的乐观锁操作
我们可以另起一个客户端模拟插队线程
另起客户端
线程1

127.0.0.1:6379> watch money //监控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 use 20
QUEUED
127.0.0.1:6379(TX)>  //此时事务并没有执行,之后模拟线程2插队

线程2

127.0.0.1:6379> INCRBY money 500 //修改了线程一中监视的money
(integer) 580

回到线程1,执行事务

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 use 20
QUEUED
127.0.0.1:6379(TX)> exec //执行事务之前,线程2修改了money的值添加了500,这个时候就会导致事务执行失败
(nil)//没有结果,说明事务执行失败
127.0.0.1:6379> get money //线程2的修改生效了
"580"
127.0.0.1:6379> get use //还是只使用了20块钱,说明线程1执行失败,数值未被修改
"20"

1.可以解锁获取最新值,然后再加锁进行事务
2.unwatch进行解锁

注:无论执行是否成功,每次提交执行exec之后都会自动释放锁

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由半码博客整理,本文链接:https://www.bmabk.com/index.php/post/81920.html

(0)
小半的头像小半

相关推荐

半码博客——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!