> 文档中心 > 猿创征文|Redis事务问题

猿创征文|Redis事务问题


✨ Redis事务问题

  • 1.Redis事务基本介绍
  • 2.Redis事务的基本操作
    • 2.1开启事务
    • 2.2执行事务
    • 2.3取消事务
    • 2.4操作演示
    • 2.5事务的错误处理
    • 2.6事务的工作流程
  • 3.乐观锁和悲观锁
    • 3.1乐观锁
    • 3.2悲观锁
    • 3.3watch key
    • 3.4unwatch
  • 4.Redis事务的三大特性
  • 5.Redis事务——分布式锁
    • 5.1场景分析
    • 5.2解决方案
    • 5.3加锁忘记解锁的情景

📃个人主页:不断前进的皮卡丘
🌞博客描述:梦想也许遥不可及,但重要的是追梦的过程,用博客记录自己的成长,记录自己一步一步向上攀登的印记
🔥个人专栏:微服务专栏

1.Redis事务基本介绍

1️⃣redis事务就是一个命令执行的队列,将一系列预定义命令包装成一个整体(一个队列)。当执行时,一次性按照添加顺序依次执行,中间不会被打断或者干扰。
2️⃣一个队列中,一次性、顺序性、排他性的执行一系列命令
3️⃣redis事务在执行的过程中,不会被其他客户端发送来的命令请求所打断。
4️⃣Redis事务的主要作用就是串联多个命令防止别的命令插队。

猿创征文|Redis事务问题

2.Redis事务的基本操作

从输入Multi命令开始,输入的命令都会依次进入命令队列中,但不会执行,直到输入Exec后,Redis会将之前的命令队列中的命令依次执行。
组队的过程中可以通过discard来放弃组队。

2.1开启事务

  • multi用来开启事务
  • 作用:用来设定事务的开启位置,后续的指令都会加入到事务里面

2.2执行事务

  • exec用来执行事务
  • 作用:用来设定事务的结束位置,同时执行事务,和multi成对出现,成对使用
  • 加入事务的命令只是暂时进入到任务队列里面,这个时候没有马上执行,只有执行exec命令才开始执行

2.3取消事务

  • discard可以用来取消事务
  • 作用:终止当前事务的定义,发生在multi之后,exec之前

2.4操作演示

猿创征文|Redis事务问题

2.5事务的错误处理

🔥组队中某个命令出现了报告错误,执行时整个的所有队列都会被取消。
🔥如果执行阶段某个命令报出了错误,则只有报错的命令不会被执行,而其他的命令都会执行,不会回滚。

2.6事务的工作流程

猿创征文|Redis事务问题

3.乐观锁和悲观锁

乐观锁和悲观锁主要是用来解决并发场景下的数据冲突问题。比如说买汽车票,同一时间有很多人都在抢同一张票,但是最后只能有一个人成功抢到。

3.1乐观锁

乐观锁从字面意思我们就知道是很乐观的意思,在操作数据的时候很乐观,认为别人不会同时修改数据,但是在最后更新修改的时候,会检查一下操作期间有没有人修改过数据,可以用版本号来控制。如果没有的话,就执行更新操作,如果操作期间有人修改过数据的话,就放弃更新操作。乐观锁适用于多读的应用类型,这样可以提高吞吐量。Redis就是利用这种check-and-set机制实现事务的。

3.2悲观锁

使用悲观锁的话,在操作数据的时候觉得很悲观,认为别人会同时修改数据所以在操作数据的时候直接把数据给锁住,一直到操作完成才释放锁。上锁期间,其他人不能够修改数据。传统的关系型数据库里边就用到了很多这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁。

3.3watch key

在执行multi之前,先执行watch key1 [key2],可以监视一个(或多个) key ,如果在事务执行之前这个(或这些) key 被其他命令所改动,那么事务将被打断。
猿创征文|Redis事务问题

3.4unwatch

取消 WATCH 命令对所有 key 的监视。
如果在执行 WATCH 命令之后,EXEC 命令或DISCARD 命令先被执行了的话,那么就不需要再执行UNWATCH 了。

4.Redis事务的三大特性

  • 单独的隔离操作
    • 事务中的所有命令都会序列化、按顺序地执行。事务在执行的过程中,不会被其他客户端发送来的命令请求所打断。
  • 没有隔离级别的概念
    • 队列中的命令没有提交之前都不会实际被执行,因为事务提交前任何指令都不会被实际执行
  • 不保证原子性
    • 如果执行阶段某个命令报错,则只有报错的命令不会被执行,而其他的命令都会执行,不会回滚。

5.Redis事务——分布式锁

5.1场景分析

天猫双11热卖过程中,对已经卖完的货物追加补货,而且补货完成,客户购买热情高涨,3秒内把所有物品购买完。此次补货已经把库存全部都清空了,那么我们要怎么避免最后一件商品不被多人同时购买?(超卖问题)
🔥使用watch监控的是key有没有改变,这里已经不能解决问题了,我们需要监控的是具体数据
🔥redis虽然是单线程的,但是多个客户端对同一个数据同时进行操作的时候,要怎么避免不会被同时修改呢?

5.2解决方案

使用setnx来设置一个公共的锁,利用setnx命令的返回值特征,如果本来就存在值的话,返回设置失败,没有值则返回设置成功
🔥setnx lock-key value
🔥 利用setnx命令的返回值特征,有值则返回设置失败,无值则返回设置成功
📖对于返回设置成功的,拥有控制权,进行下一步的具体业务操作
📖 对于返回设置失败的,不具有控制权,排队或等待
操作完毕通过del操作释放锁
🔥注意:上述解决方案是一种设计概念,依赖规范保障,具有风险性

5.3加锁忘记解锁的情景

我们知道锁是用户加的,如果某一个用户操作对应客户端死机了,要怎么办?
📖因为锁操作是用户控制加锁解锁,所以会存在加锁以后忘记解锁的情况
📖需要解锁操作不能仅仅依赖用户控制,系统级别要给出对应的保底处理方案(如果在规定时间内锁一直不释放,我们可以把锁去掉,也就是给锁设定有效期)

🔥使用 expire 为锁key添加时间限定,到时不释放,放弃锁
猿创征文|Redis事务问题