首页 > 技术文章 > redis专题十一:redis的事务

leijisong 2020-11-16 23:04 原文

一、事务的简介

在执行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的删除策略

 

推荐阅读