您的位置:首页 > 数据库 > Redis

Redis事务

2017-07-03 21:24 375 查看
一、是什么?

reids中的事务与数据库中的事务类似,但是又不是完全相似。换句话说,redis对事务是部分支持的,下面会讲解到。首先,reids的事务同样可以一次性执行多个命令,本质是一组命令的集合。一个事务中的所有命令都会序列化,按顺序的串行化执行而不会被其他命令插入,不允许加塞。
二、能干嘛?

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

三、怎么玩?

1、正常执行:

首先执行MULTI命令开启事务,顺序执行多个写命令或者读命令,此时执行的命令并不会马上执行,而是顺序将命令加入queue队列中,直到执行EXEC命令后才会一次性执行(正常执行事务要求命令符合规范且存在)



2、放弃事务:

执行MULTI命令开启事务,若执行多条写入命令或者读命令后(此时同样是未执行的),若此时执行DISCARD命令,之前入队的命令将全部失效



3、全体连坐:(这一点和数据库事务类似)

开启事务之后,依次执行命令。此时有一条错误的命令,指输入后报错了,此时继续输入命令依然是正常入队,但是执行EXCE命令后报错,先前入队的执行命令都是无效的。



4、怨头债主:

开启事务之后,同样依次执行命令。此时有一条无语法错误(指命令符合规范)但是在运行时会报异常的命令,同样是正常入队,其他命令都正确且可执行,所有命令输入回车后均入队且未报错。在执行EXCE后那条(运行时异常的命令)会报错,其他命令依然正确执行。类似于Java编译时异常和运行时异常。比如那条命令好比 int a=10/0,此时并不会报异常,但是执行时报异常



key1的值为v1,对key1执行INCR命令所以报错
getset key3 v3 指将给定 key(v3) 的值设为 value ,并返回 key 的旧值(无旧值则返回nil)。

两种区别的关键在于: 命令入队过程中是否有报错,若有报错则“连坐”,无则哪条命令报错哪条命令执行失败,其他命令正常执行成功。因此可以说redis对事务是部分支持。(有‘怨头债主’的存在)

5、watch监控:

首先需要了解悲观锁、乐观锁和CAS(Check And Set)的概念

悲观锁:悲观锁(Pessimistic Lock), 顾名思义,就是很悲观,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会block直到它拿到锁。传统的关系型数据库里边就用到了很多这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁

乐观锁:乐观锁(Optimistic Lock), 顾名思义,就是很乐观,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号等机制。乐观锁适用于多读的应用类型,这样可以提高吞吐量,

乐观锁策略:提交的版本必须大于当前记录的版本才能执行(若提交版本低于当前记录的版本说明在自己修改数据时别人也修改过数据并且先于自己提交)

我们可以通过模拟信用卡可用余额和欠额。

1)无加塞篡改的情况:

首先初始化可用余额balance和欠额debt,初始化后先开启key监控再MULTI开启事务,保证两笔金额变动在同一个事务内。然后使可用余额balance减少20,对应欠额debt加上20,模拟命令执行完后数据无任何差错,因为这种情况是只有自己一个人对该张卡进行操作。



2)加塞篡改的情况:

此时的balance为80,debt为20。若此时启动另外一终端取名为第二终端(模拟另外一个人也在操作该张信用卡),第二终端在第一终端已经对balance监控的情况下对可用余额进行操作,比如对balance增加至1000。这时候第一终端再对余额和欠额开启事务操作变动时将会失效。(第一终端的 watch balance先于第二终端的set balance 1000)

第二终端:



第一终端:



3)比如在第二次中开启了监控后,准备再次变动可用余额和欠额的情况下知道了该卡已经被操作过了。则可以执行unwatch命令,该命令一执行会取消先前对所有key值的监控

总结:Watch指令,类似乐观锁,事务提交时,如果Key的值已被别的客户端改变,比如某个list已被别的客户端push/pop过了,整个事务队列都不会被执行

四、redis事务的三阶段

开启:以MULTI开启一个事务

入队:将多个命令入队到哦事务中,接到这些命令并不会立即执行,而是放到等待执行的事务队列里面

执行:由EXEC命令触发事务

五、redis事务的特性

1、单独的隔离操作:事务中的所有命令都会序列化、按顺序的执行。事务在执行的过程中,不会被其他客户端发送来的命令请求所打断

2、没有隔离级别的概念:队列中的命令没有提交之前都不会实际的被执行,因为事务提交前任何指令都不会被实际执行,也就不存在“事务内的查询要看到事务里的更新,在事务外查询不能看到”的问题

3、不保证原子性:redis同一个事务中,如果有一条命令执行失败,其后的命令任然会被执行,没有回滚(比如上面提到的“全体连坐”)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息