redis学习之--Redis的部分支持事务(六)

一提到事务,我们想起什么?乐观锁、悲观锁、行锁、页锁、表锁等等

一、官网介绍

官网:https://redis.io/topics/transactions
中文官网:http://www.redis.cn/topics/transactions.html

二、是什么

可以一次执行多个命令,本质是一组命令的集合。一个事务中的所有命令都会序列化,按顺序地串行化执行而不会被其它命令插入。通俗来说,就是不加塞。

三、能干嘛

一个队列中,一次性、顺序性、排他性的执行一系列命令。

四、怎么玩

4.1、常用命令

①discard:取消事务,放弃执行事务块内的所有命令
清空执行队列,并放弃对事务的操作。
②EXEC:执行所有事务块的命令
返回一个数组,数组中的每个元素都是执行每条命令产生的回复,顺序一致
③MULTI:标记一个事务块的开始
MULTI命令用于开启一个事务,它总是返回ok。ok并不是真的执行成功,只是表明自己收到了。MULTI执行之后,可以发送多条命令,但这些命令不会立即执行,而是被放到一个队列quene中。当EXEC命令执行时,队列中的命令才会被执行。
入队,并不是执行。相当于你在商场购物,MULTI是加入购物车,可以多次加入购物车,EXEC是最后的结算
④UNWATCH:取消WATCH命令对所有key的监视
⑤WATCH key [key...]:监视一个(或多个)key,如果在事务执行之前这些key被其他命令所改动,那么事务将被打断。

4.2、正常执行

 
MULTI执行之后总是返回ok。执行set、get等命令返回QUEUED,表示已入队列,等待被执行。
相当于刷微博。三个人评论,一个人查看。在一个原子操作里面。

4.3、放弃事务

4.4、全体连坐(原子性)


原子性。一个命令执行失败,事务中所有命令都会失败。

4.5、冤头债主


这节和上一节可以一起看。类比Java中的编译时报错和运行时报错。
执行EXEC后仅incr k1报错了,其他命令照常执行。
所以说,redis对事务是部分支持

使用事务时可能会遇上以下两种错误:
1、执行EXEC之前,入队的命令报错,如:命令语法错误或内存不足等。
2、执行EXEC之后失败。如:处理了错误类型的键,给字符串数据incr等。
对于第一种错误,检查命令入队所得的返回值:命令入队成功返回QUEUED,命令入队失败直接报错error。从Redis 2.6.5开始,当redis检测到有入队失败命令后,就会停止并取消这个事务。
对于第二种错误,并没有特殊处理:即使事务中某些命令执行失败了,其他命令仍正常进行。
这就是redis部分支持事务的原因。

为什么redis不支持回滚呢?
1、对于第一种错误。从实用性来讲,失败的命令是由于错误编程造成的,而这些错误应该在开发的过程中被发现,而不应该出现在生产环境中。意思就是:就不应该在生产环境里出现,哪里需要什么回滚。
2、不支持回滚,可以保持Redis内部的简单且快速。

4.6、watch监控

提到Redis的watch命令,不得不说一说什么是乐观锁,什么是悲观锁。

悲观锁(Pessimistic Lock), 顾名思义,就是很悲观,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会阻塞(block)直到它拿到锁。传统的关系型数据库里边就用到了很多这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁。
悲观锁,我认为你动了我的东西,为了不出事,我把整张表都锁了,只运行我自己用。。。并发性极差,但一致性最好
但想想实际情况,一张表我只改45行,但我悲观锁锁了整张表,而别人要改78行,在某些情况夏不是很实用,所以又有了行锁。即乐观锁。

乐观锁(Optimistic Lock), 顾名思义,就是很乐观,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号等机制。乐观锁适用于多读的应用类型,这样可以提高吞吐量。乐观锁策略:提交版本必须大于记录当前版本才能执行更新。
乐观锁,在每条记录后面加一个version标记,每次提交后version也随之变化。提交的时候发现自己的version与 该行最新的version不一致,则认为此行已经被修改过,提交失败。然后再次获取最新的version,直到提交时版本一致才能提交成功。

工作中用乐观锁多。乐观锁与悲观锁,类似行锁和表锁。是并发性和一致性的对立。
悲观锁的使用:如数据库的备份

什么是CAS?check-and-set,顾名思义,先检查再提交。类似乐观锁。WATCH命令可以为Redis事务提供CAS行为
被watch键监视,如果某个或某些键被改动了,那么整个事务就会被取消,执行EXEC返回nil
对键的监视从watch执行之后开始生效,直到调用EXEC为止。也就是说,不管执行成功与否,一旦执行了EXEC之前加的监控锁都会被自动取消。

以花呗模式为例:默认设置你的  初始额度balance=100,初始需要还款debt=0。
情况一、无加塞篡改,先监控再开启multi,保证两笔金额变动在同一个事务内。花出去20后,balance=80,debt=20

情况二、有加塞篡改。监控了key,如果key被修改了,则后面的事务的执行失效。相当于突然涨了花呗额度800。

情况三、手动取消对所有键的监控 unwatch

小结:
1、Watch命令,类似乐观锁。事务提交时,如果Key的值已被别的客户端改变,比如某个list已被别的客户端push/pop过了,整个事务队列都不会被执行。
2、通过WATCH命令在事务执行之前监控了多个Keys,倘若在WATCH之后有任何Key的值发生了变化,EXEC命令执行的事务都将被放弃,同时返回Nullmulti-bulk应答以通知调用者事务执行失败。

五、三阶段

  1. 开启:以MULTI开始一个事务
  2. 入队:将多个命令入队到事务中,接到这些命令并不会立即执行,而是放到等待执行的事务队列里面
  3. 执行:由EXEC命令触发事务

六、三特性

  1. 单独的隔离操作:事务中的所有命令都会序列化、按顺序地执行。事务在执行的过程中,不会被其他客户端发送来的命令请求所打断。
  2. 没有隔离级别的概念:队列中的命令没有提交之前都不会实际的被执行,因为事务提交前任何指令都不会被实际执行,也就不存在”事务内的查询要看到事务里的更新,在事务外查询不能看到”这个让人万分头痛的问题
  3. 不保证原子性:redis同一个事务中如果有一条命令EXEC后执行失败,其后的命令仍然会被执行,没有回滚

七、脚本

从定义上来讲,Redis中的脚本就是一种事务,所以任何在事务里完成的事在脚本里也能完成。而且,一般来说,脚本更为简单和速度更快。但是我们短时间内并不打算使用脚本替代事务操作。。。所以还是学好事务吧

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值