前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Redis事务与乐观锁

Redis事务与乐观锁

作者头像
Andromeda
发布2024-01-05 09:35:44
1210
发布2024-01-05 09:35:44
举报
文章被收录于专栏:Andromeda的专栏Andromeda的专栏

概述

Redis 事务是一种将多个命令打包在一起执行的机制。通过使用事务,可以确保一系列命令在一次执行中依次执行,而不会被其他客户端的命令请求打断。

Redis 事务的执行分为以下几个步骤:

  1. 开启事务 :使用 MULTI 命令开启一个事务。之后的命令都会被添加到事务队列中,而不会立即执行。
  2. 添加命令 :在 MULTI 和 EXEC 命令之间,可以添加任意数量的 Redis 命令,这些命令会按照添加的顺序被放入事务队列中。
  3. 执行事务 :使用 EXEC 命令执行事务。Redis 会按照事务队列中命令的顺序依次执行这些命令。在执行事务期间,Redis 不会处理其他客户端的命令请求。
  4. 事务结果 :执行事务后,Redis 会返回事务中每个命令的执行结果。结果的顺序与命令在事务队列中的顺序相对应。
  5. 取消事务 :在开启事务后,可以使用 DISCARD 命令取消事务,丢弃事务队列中的所有命令。

Redis 事务的一个重要特性是乐观锁。在执行事务期间,Redis 不会对数据进行锁定或阻塞其他客户端操作,而是在执行事务时记录了事务执行期间所依赖的键的状态,如果在执行 EXEC 命令之前检测到这些键的状态发生了变化,那么事务将会被中断并放弃执行。

需要注意的是,Redis 的事务是原子性的,要么全部执行成功,要么全部放弃执行。如果在事务执行期间出现错误,事务中的所有命令都不会被执行,并且不会对数据产生任何影响。Redis 事务的应用场景包括批量操作、原子操作、队列操作等,通过将多个命令打包在一起执行,可以减少网络通信开销,提高性能,并保持一致性。

乐观锁和悲观锁

悲观锁

  • 悲观锁的思想是,在整个数据操作过程中,将数据进行加锁,以阻止其他事务或线程对数据进行修改。
  • 当一个事务获取了悲观锁后,其他事务需要等待锁被释放才能继续操作,从而保证了数据的一致性。
  • 悲观锁适用于并发冲突较多、写操作频繁的场景。
  • 在关系型数据库中,使用行级锁或表级锁实现悲观锁。

乐观锁

  • 乐观锁的思想是,假设多个事务之间不会发生冲突,每个事务在修改数据时不会阻塞其他事务,只在提交时检查是否有冲突。
  • 乐观锁通过在数据记录中添加版本号或时间戳等标识,用于检测数据是否被其他事务修改过。
  • 当一个事务提交时,会比较当前数据的版本号与事务开始时获取的版本号是否一致,如果一致则提交成功,否则表示数据已被其他事务修改,需要进行冲突处理。
  • 乐观锁适用于并发冲突较少、读操作频繁的场景,避免了数据的阻塞等待。
  • 在关系型数据库中,使用版本号或时间戳实现乐观锁。

在实际应用中,选择使用悲观锁还是乐观锁取决于具体的需求和场景。悲观锁可以确保数据的一致性,但可能带来较高的开销和性能影响。乐观锁则通过乐观的假设减少了锁的竞争,提高了并发性能,但需要在冲突发生时进行额外的处理。

事务的错误处理

出现语法错误时,EXEC 后会直接返回错误,语法正确的命令也不会执行

代码语言:javascript
复制
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> SET key
(error) ERR wrong number of arguments for 'set' command
127.0.0.1:6379> SET name cx
QUEUED
127.0.0.1:6379> EXEC
(error) EXECABORT Transaction discarded because of previous errors.

出现运行错误时,比如使用集合的命令操作字符串,这种错误在执行之前无法被发现,所以这种情况下正确的命令会被执行。Redis 的事务机制并不支持事务回滚(rollback)操作,因此当出现事务运行错误需要自己收拾烂摊子。

代码语言:javascript
复制
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> SET name caixing
QUEUED
127.0.0.1:6379> SADD name cx
QUEUED
127.0.0.1:6379> EXEC
1) OK
2) (error) WRONGTYPE Operation against a key holding the wrong kind of value

WATCH 命令

WATCH 命令用于实现乐观锁机制,它可以在事务执行之前监视一个或多个键。WATCH 命令会监视指定的键,如果在执行事务期间有其他客户端修改了被监视的键,那么当前事务将被打断,不会执行,可以通过检查执行 EXEC 命令的返回值来判断是否执行了事务。

使用 WATCH 命令监视一个或多个键:

代码语言:javascript
复制
WATCH key1 key2 ...

可以指定一个或多个键来监视。一旦执行了 WATCH 命令,Redis 会将这些键标记为被监视状态。

比如说如果要自己利用 GET 和 SET 实现 INCR 函数,伪代码如下所示。这段代码可能出现竞态条件,key 的原始值为 6,期望情况应该是将 key 变为 8,但是如果两个客户端同时(在对方尚未返回时)开始执行这段代码,那么最后 key 是 7。

代码语言:javascript
复制
$val = GET $key
if $val is null
    $val = 0
$val = $val + 1
SET $key $val

虽然事务提供了原子性,但是由于事务每条命令的执行结果是同时返回的,所以不适用这种前后具有依赖关系的命令,为了解决这个问题,可以使用 WATCH 来实现 GET 获得键值后不允许其他客户端修改键以防止竞态条件。

在执行事务前使用 WATCH 监视 key,在执行事务前 key 发生了改变,变成了 3,因此事务未执行。WATCH 的监控一直持续到 EXEC 命令。

代码语言:javascript
复制
127.0.0.1:6379> SET key 1
OK
127.0.0.1:6379> WATCH key
OK
127.0.0.1:6379> SET key 2
OK
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> SET key 3
QUEUED
127.0.0.1:6379> EXEC
(nil)
127.0.0.1:6379> GET key
"2"

修改刚刚的伪代码如下。

代码语言:javascript
复制
WATCH $key
$val = GET $key
if $val is null
    $val = 0
$val = $val + 1
MULTI
SET $key $val
EXEC
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 概述
  • 乐观锁和悲观锁
  • 事务的错误处理
  • WATCH 命令
相关产品与服务
云数据库 Redis
腾讯云数据库 Redis(TencentDB for Redis)是腾讯云打造的兼容 Redis 协议的缓存和存储服务。丰富的数据结构能帮助您完成不同类型的业务场景开发。支持主从热备,提供自动容灾切换、数据备份、故障迁移、实例监控、在线扩容、数据回档等全套的数据库服务。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档