一、事务的简介
在执行redis命令的时候,多条连续执行的指令可能会被干扰,打算。比方说A客户端执行了set name libai , 然后想要去执行get name。但是这个时候B客户端执行了set name dufu.这个时候A客户端获得的结果并非自己期待设置的值“libai”。这个数据产生了偏差。
redis的事务就是一个命令执行的队列,将一系列的命令包装成一个整体,在执行的时候,按照添加的顺序依次执行,中间不会被打断或者干扰。
二、事务的基本操作
- 开启事务:multi 作用:设定事务开启的位置,此指令执行后,后续的所有指令均加入事务中
- 执行事务:exec 作用:设定事务的结束位置,同时执行事务,与multi成对出现使用
注意:加入事务的命令暂时进入到任务队列中,并没有立即执行,只有执行exec命令才开始执行;
如果事务定义的过程中出现自己误定义的内容,可以取消事务:
- 取消事务:discard 作用:终止当前事务定义,发生在multi之后,exec之前。
三、事务的工作流程
注意:如果是在事务状态下,multi指令识别之后,会创建一个队列去接受接下来的指令,直到exec时候执行队列中的所有指令并返回每一条指令的执行结果;如果是discard,则销毁之前创建的队列。
四、事务操作的注意事项
如果事务过程中,命令输错怎么办?
(1)如果事务输入过程中有语法错误,那么所有指令皆不执行,包括那些之前输入正确的指令
(2)如果是执行事务过程中出现错误,即指令语法正确,但是无法正确的执行,如对list进行incr的操作,结果是能够正确运行的命令会执行,运行错误的指令不被执行
注意:已经执行完成的指令数不会自动回滚,需要手工回滚;
手工进行回滚操作时:
- 注意手工记录操作过程中被影响的数据之前的状态
- 设置指令恢复所有的被修改项
五、锁
5.1 watch
举例1:比方说我们卖货,对于已经售罄的货物需要进行补货,有甲乙丙三个业务员可以操作,补货的时候可能会涉及一系列的多个操作,保证不能重复进行?
分析:相当于多个客户端同时操作同一份数据,并且数据被操作修改之后,将不适合继续操作;同时,在操作之前锁定要操作的数据,一旦发生变化,终止当前操作
解决:对key添加监视锁,在指定exec前如果key发生了变化,终止事务执行;
指令:watch key1 [key2]
对应相应的取消对key的监视:
指令:unwatch
5.2 setnx
举例2:在场景1下,已经补货结束,但是购买力很强,一下子就卖完了,如何避免最后一件商品不被多人同时购买?
分析:使用watch监控一个key有没有改变已经不能解决当前的问题,此处要监控的是具体的数据;虽然redis是单线程的,但是多个客户端对同一个数据进行操作,如何才能避免不被同时修改呢?
解决:使用setnx设置一个公共锁
指令:setnx lock-key value
利用setnx的返回值特征,有值则返回设置失败,没有则返回设置成功
对于设置成功的,进行下一步操作;设置失败的,排队或者等待
操作完毕后,del掉这个操作锁
注意:这个解决方案依赖规范保证,如果大家不是基于的setnx的key不是一个,那么,完蛋。
5.3 死锁
场景:锁是加上了,但是持有锁之后一直没释放,那么其他人一直也就操作不了,如何处理?
解决:使用expire为锁key添加时间限定,超时了释放锁;
指令:expire lock-key second 设置的时间为秒
pexpire lock-key milliseconds 设置的时间为毫秒
注意:操作通常都是毫秒级甚至更低,一般锁的超时时间不宜设置很大,结合业务来设定;
一般推荐:最大耗时*1.2 + 网络耗时*1.1,当然如果这两者有一个数量级远大于另一者,另外一个差不读就可以忽略了。
这一专题就到这里,下一专题写:redis的删除策略