千家信息网

Redis怎么使用乐观锁保证数据一致性

发表于:2025-01-20 作者:千家信息网编辑
千家信息网最后更新 2025年01月20日,这篇文章主要介绍了Redis怎么使用乐观锁保证数据一致性,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。场景在 Redis 中经常会存在
千家信息网最后更新 2025年01月20日Redis怎么使用乐观锁保证数据一致性

这篇文章主要介绍了Redis怎么使用乐观锁保证数据一致性,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。

场景

在 Redis 中经常会存在这么一种情况,读取某一个 key 的值,做一些业务逻辑处理,然后根据读取到的值来计算出一个新的值,重新 set 进去。

如果客户端 A 刚读取到 key 值,紧接着客户端 B 就修改这个 key 的值,那么就会存在并发安全的问题。

问题模拟

假设 Redis Server 有个键名为 test 的key,里面存放的是一个 json 数组 [1, 2, 3]。

下面让我们模拟一下,客户端 A 与 客户端 B 同时访问修改的情况,代码如下:

客户端 A:

class RedisClientA(username: String, password: String, host: String, port: Int) {    val jedis: Jedis    init {        val pool = JedisPool(JedisPoolConfig(), host, port)        jedis = pool.resource        jedis.auth(username, password)    }    fun update(key: String) {        val idStr = jedis.get(key)        val idList = Json.decodeFromString>(idStr)        // 等待2秒,模拟业务        TimeUnit.SECONDS.sleep(2L)        idList.add(4)        println("new id list: $idList")        jedis.set(key, Json.encodeToString(idList))    }    fun getVal(key: String): String? {        return jedis.get(key)    }}fun main() {    val key = "test"    val redisClientA = RedisClientA("default", "123456", "127.0.0.1", 6379)    redisClientA.update(key)    val res = redisClientA.getVal(key)    println("res: $res")}

客户端 B:

class RedisClientB(username: String, password: String, host: String, port: Int) {    val jedis: Jedis    init {        val pool = JedisPool(JedisPoolConfig(), host, port)        jedis = pool.resource        jedis.auth(username, password)    }    fun update(key: String) {        val idStr = jedis.get(key)        val idList = Json.decodeFromString>(idStr)        idList.add(5)        println("new id list: $idList")        jedis.set(key, Json.encodeToString(idList))    }    fun getVal(key: String): String? {        return jedis.get(key)    }}fun main() {    val key = "test"    val redisClientB = RedisClientB("default", "123456", "127.0.0.1", 6379)    redisClientB.update(key)    val res = redisClientB.getVal(key)    println("res: $res")}

客户端 A 阻塞了 2 秒,用来模拟耗时业务逻辑的处理。正在处理的时候,客户端 B 访问了 "test",并增加了 id:5。

在客户端 A 耗时业务逻辑处理完的时候,增加了 id:4,并且会覆盖掉 id:5。

最终"test" 里的内容最终如下:

CAS 来保证数据一致性

WATCH 命令可以为 Redis 事务提供 check-and-set(CAS)行为。被 WATCH 的键会被监视,并会发觉这些键是否被改动过了。如果有至少一个被监视的建在 EXEC 执行之前被修改了,那么整个事务都会被取消,EXEC 返回空(Null replay)来表示事务执行失败。我们只需要重复操作,希望在这个时间段内不会有新的竞争。这种形式的锁被称作乐观锁,它是一种非常强大的锁机制。

那么 CAS 的方式如何实现呢?我们只需要把 RedisClientA 的 update() 方法中的代码修改如下:

fun update(key: String) {    var flag = true    while (flag) {        jedis.watch(key)        val idStr = jedis.get(key)        val idList = Json.decodeFromString>(idStr)        // 等待2秒,模拟业务        TimeUnit.SECONDS.sleep(2L)        val transaction = jedis.multi()        idList.add(4)        println("new id list: $idList")        transaction.set(key, Json.encodeToString(idList))        transaction.exec()?.let {            flag = false        }    }}

最终 "test" 的内容如下:

可见我们通过使用 WATCH 和 TRANACTION 命令,采用 CAS 乐观锁的方式实现了数据的一致性。

感谢你能够认真阅读完这篇文章,希望小编分享的"Redis怎么使用乐观锁保证数据一致性"这篇文章对大家有帮助,同时也希望大家多多支持,关注行业资讯频道,更多相关知识等着你来学习!

客户 客户端 业务 一致 乐观 一致性 数据 篇文章 处理 保证 事务 逻辑 代码 内容 同时 命令 情况 方式 时候 问题 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 重庆安卓软件开发平台 软件开发环境包括哪些内容 浪潮高密度服务器怎么安装 火影忍者下载软件开发 软件开发中需要说明的问题 360网络安全学院渗透 数据库所有用户连接不上 管理服务器连接不上网 华为互联网科技产业总部基地项目 服务器维护检查表 共建分布式网络安全大脑周鸿祎 马鞍山博雅软件开发有限公司 焱寿互联网科技有限公司 朝阳服务器回收中心 大型彩票使用那种数据库 手机客户端app修改数据库 怎么画网络安全手抄报七年级步骤 医院信息系统his数据库 服务器ip封禁怎么解除 合肥光学成像仿真软件开发 计算机二级数据库vfp 电视设备服务器指的是什么 网络安全设备 千兆 UK可以代替航天服务器 乌鲁木齐服务器设备维保 姑苏区管理软件开发诚信合作 网络技术课程 中职 格尔木软件开发有限公司 两台服务器部署kafka集群 华为驱动软件开发
0