Redis中的事务和原子性

在 Redis 中,事务原子性 是两个关键概念,用于保证多个操作的一致性和可靠性。以下是 RedissonSpring Data Redis 在处理原子性操作时的区别与对比:


1. Redis 的原子性机制

Redis 本身通过以下方式保证原子性:

  • 单线程模型:所有命令按顺序执行,单个命令默认是原子的。
  • 事务(MULTI/EXEC:将多个命令打包为一个事务,按顺序执行,但不支持回滚。
  • Lua 脚本:通过 EVAL 执行的 Lua 脚本在 Redis 中是原子执行的,适合复杂逻辑。

2. Redisson 的分布式集合操作(如 putIfAbsent

Redisson 封装了 Redis 的分布式数据结构(如 RMapRLock 等),其操作默认是线程安全的,并且内部通过 Lua 脚本Redis 事务 保证原子性。

示例:Redisson 的 putIfAbsent
RMap<String, String> map = redisson.getMap("myMap");
String value = map.putIfAbsent("key", "value");
  • 实现原理
    Redisson 内部通过 Lua 脚本实现 putIfAbsent,逻辑类似:
    if redis.call("EXISTS", KEYS[1]) == 0 thenreturn redis.call("SET", KEYS[1], ARGV[1])
    elsereturn nil
    end
    
  • 原子性保障
    由于 Lua 脚本在 Redis 单线程中执行,整个操作是原子的,无需开发者手动处理事务。
优点
  • 简化开发:开发者无需关注底层的 Lua 脚本或事务。
  • 开箱即用:适合分布式锁、队列、集合等常见场景。
适用场景
  • 快速实现分布式集合操作(如 putIfAbsentfastPut)。
  • 需要线程安全的分布式数据结构(如 RMapRSet)。

3. Spring Data Redis 的原子性保障

Spring Data Redis 提供了对 Redis 的原生操作支持,但需要开发者通过 Lua 脚本事务 显式保证原子性。

示例:通过 Lua 脚本实现 putIfAbsent
DefaultRedisScript<String> script = new DefaultRedisScript<>();
script.setScriptText("if redis.call('EXISTS', KEYS[1]) == 0 then return redis.call('SET', KEYS[1], ARGV[1]) else return nil end");
script.setResultType(String.class);String result = redisTemplate.execute(script, Collections.singletonList("key"), "value");
示例:通过事务实现原子性
redisTemplate.setEnableTransactionSupport(true);
TransactionStatus status = redisTemplate.getTransactionManager().beginTransaction();
try {redisTemplate.opsForValue().set("key", "value");redisTemplate.boundValueOps("key").get();redisTemplate.getTransactionManager().commit(status);
} catch (Exception e) {redisTemplate.getTransactionManager().rollback(status);
}
原子性保障
  • Lua 脚本:通过 EVAL 执行的脚本在 Redis 中是原子的。
  • 事务MULTI/EXEC 保证命令按顺序执行,但不支持回滚。
优点
  • 灵活性:可直接使用 Redis 的原生命令和高级特性。
  • 性能优化:通过管道(Pipeline)减少网络往返。
适用场景
  • 高频读写缓存(如热点数据)。
  • 复杂业务逻辑(如排行榜、分布式计数器)。
  • 需要直接调用 Redis 的 SCANBITFIELD 等高级命令。

4. 对比总结

维度RedissonSpring Data Redis
原子性保障方式内部封装 Lua 脚本或 Redis 事务,开发者无需手动处理。需要显式使用 Lua 脚本或事务。
开发复杂度简单,直接调用 Java 集合接口(如 putIfAbsent)。复杂,需自行编写 Lua 脚本或事务逻辑。
性能封装可能引入额外开销(如序列化),适合中低并发场景。原生 Redis 命令调用,性能更高,适合高并发场景。
适用场景分布式锁、队列、集合操作等常见场景。缓存、排行榜、复杂数据结构操作等高性能场景。
线程安全所有 API 默认线程安全。Lettuce 连接线程安全,但需注意多线程操作 Redis 命令的原子性。

5. 选择建议

  • 优先使用 Redisson
    如果需要快速实现 分布式集合操作(如 putIfAbsentremoveIfPresent)或 分布式锁(如 RLock),优先选择 Redisson。其封装的 Lua 脚本和事务逻辑隐藏了复杂性,适合快速开发。

  • 优先使用 Spring Data Redis + Lua
    如果需要 高性能缓存复杂业务逻辑(如排行榜、分布式计数器),使用 Spring Data Redis 并结合 Lua 脚本。通过精细控制 Redis 命令,可以优化性能并充分利用 Redis 的原生特性。

  • 混合使用注意事项

    • 连接池分离:Redisson 和 Spring Data Redis 使用不同的连接池,避免资源竞争。
    • 键名命名规范:避免键名冲突(如 Redisson 使用前缀 redisson:,Spring Data Redis 使用前缀 spring:)。
    • 集群模式下的原子性:确保 Lua 脚本操作的 key 在同一个 slot,否则原子性无法保证。

6. 实际案例

案例 1:分布式计数器
  • Redisson

    RAtomicLong counter = redisson.getAtomicLong("counter");
    counter.incrementAndGet(); // 原子操作
    
  • Spring Data Redis

    DefaultRedisScript<Long> script = new DefaultRedisScript<>();
    script.setScriptText("return redis.call('INCR', KEYS[1])");
    script.setResultType(Long.class);
    Long count = redisTemplate.execute(script, Collections.singletonList("counter"));
    
案例 2:分布式锁
  • Redisson

    RLock lock = redisson.getLock("lock");
    lock.lock();
    try {// 临界区操作
    } finally {lock.unlock();
    }
    
  • Spring Data Redis

    String lockKey = "lock";
    Boolean isLocked = redisTemplate.opsForValue().setIfAbsent(lockKey, "1", 10, TimeUnit.SECONDS);
    if (Boolean.TRUE.equals(isLocked)) {try {// 临界区操作} finally {redisTemplate.delete(lockKey);}
    }
    

通过合理选择工具和实现方式,可以充分发挥 Redis 的原子性保障能力,构建高效、可靠的分布式系统。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/80724.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Apollo10.0学习——planning模块(8)之scenario、Stage插件详解二

scenario插件 插件总览插件ValetParkingScenario阶段一&#xff1a;StageApproachingParkingSpotprocess()方法 阶段二&#xff1a;StageParkingprocess()方法FinishStage方法 插件PullOverScenarioIsTransferable: 场景切入条件 代码逻辑阶段一&#xff1a;PullOverStageAppro…

JVM的面试相关问题

面试中的相关问题主要是三块 1.JVM 内存区域划分 2.JVM 的类加载机制 3.JVM 的垃圾回收机制 JVM Java虚拟机 VM Virtual Machine 虚拟机,用 软件 来 模拟 硬件 传统意义上的"虚拟机" 更多指的是 VMWare, Virtual Box, Hyper-V, KVM(构造出虚拟的电脑,甚至可以…

win10使用nginx做简单负载均衡测试

一、首先安装Nginx&#xff1a; 官网链接&#xff1a;https://nginx.org/en/download.html 下载完成后&#xff0c;在本地文件中解压。 解压完成之后&#xff0c;打开conf --> nginx.config 文件 1、在 http 里面加入以下代码 upstream GY{#Nginx是如何实现负载均衡的&a…

[特殊字符]车牌识别相机,到底用在哪?

停车场管理&#xff0c;快速通行不是梦 停车场大概是车牌识别相机最常见的 “工作岗位” 啦&#xff01;以前进出停车场&#xff0c;取卡、刷卡、人工收费&#xff0c;一系列操作下来&#xff0c;高峰期的时候真的能把人等得不耐烦&#x1f62b; 现在有了车牌识别相机&#xff…

nosqlbooster pojie NoSQLBooster for MongoDB

测过可用&#xff0c;注意 asar的安装使用报错改用 npx asar extract app.asar app 路径 C:\Users{computerName}\AppData\Local\Programs\nosqlbooster4mongo\resources npm install asar -g asar extract app.asar app 打开shared\lmCore.js 修改MAX_TRIAL_DAYS3000 修改…

组态王通过开疆智能profinet转ModbusTCP网关连接西门子PLC配置案例

本案例是组态王通过使用开疆智能研发的Profinet转ModbusTCP网关采集西门子1200PLC中数据的案例。 网关配置 首先来配置网关的参数&#xff0c;打开网关配置软件“Gateway Configuration Studio” 由于组态王那侧设定为ModbusTCP客户端所以网关作为ModbusTCP服务器。新建项目…

大模型服务如何实现高并发与低延迟

写在前面 大型语言模型(LLM)正以前所未有的速度渗透到各行各业,从智能客服、内容创作到代码生成、企业知识库,其应用场景日益丰富。然而,将这些强大的 AI 能力转化为稳定、高效、可大规模应用的服务,却面临着巨大的挑战,其中高并发处理能力和低响应延迟是衡量服务质量的…

k8s监控方案实践补充(二):使用kube-state-metrics获取资源状态指标

k8s监控方案实践补充&#xff08;二&#xff09;&#xff1a;使用kube-state-metrics获取资源状态指标 文章目录 k8s监控方案实践补充&#xff08;二&#xff09;&#xff1a;使用kube-state-metrics获取资源状态指标一、Metrics Server简介二、kube-state-metrics实战部署1. 创…

Manus 全面开放注册,OpenAI 发布 Codex,ChatGPT 上线 GPT-4.1!| AI Weekly 5.12-18

&#x1f4e2;本周 AI 快讯 | 1 分钟速览&#x1f680; 1️⃣ &#x1f4dd; Manus 全面开放注册 &#xff1a;无需邀请码即可注册&#xff0c;新用户免费获得 1000 积分&#xff0c;每日 300 积分免费任务。 2️⃣ &#x1f50d; 阿里 Qwen 推出「深入研究」 &#xff1a;Qw…

代理(主要是动态)和SpringAOP

代理 静态代理基于继承实现动态代理是基于接口实现 业务层每次实现转账都需要执行&#xff0c;可以把他们拿出来当成一个切面&#xff0c;自己写出一个代理类&#xff0c;让业务层只执行业务的逻辑&#xff0c;重复的代码代理类来完成&#xff0c;然后调用代理类来执行。 代理类…

uniapp打包H5,输入网址空白情况

由于客户预算有限&#xff0c;最近写了两个uniapp打包成H5的案例&#xff0c;总结下面注意事项 1. 发行–网站-PCWeb或手机H5按钮&#xff0c;输入名称&#xff0c;网址 点击【发行】&#xff0c;生成文件 把这个给后端&#xff0c;就可以了 为什么空白呢 最重要一点&#xf…

uniapp-商城-63-后台 商品列表(分类展示商品的删除)

商品列表中的数据需要进行状态管理&#xff0c;如上架、下架、删除和修改等操作。对于存在错误或后期需要重新上传的商品&#xff0c;可以通过删除操作进行处理。 具体到商品删除功能的实现&#xff0c;其基本流程如下&#xff1a;用户在前端页面点击删除按钮后&#xff0c;系统…

学习设计模式《十》——代理模式

一、基础概念 代理模式的本质【控制对象访问】&#xff1b; 代理模式的定义&#xff1a;为其他对象提供一种代理以控制对这个对象的访问&#xff1b; 代理模式的功能&#xff1a;代理模式是通过创建一个代理对象&#xff0c;用这个代理对象去代表真实的对象&#xff1b;客户端得…

阿里云web端直播(前端部分)

阿里云&#xff1a;Web播放器快速接入_视频点播(VOD)-阿里云帮助中心 import Aliplayer from aliyun-aliplayerimport aliyun-aliplayer/build/skins/default/aliplayer-min.css<div id"J_prismPlayer" style"width: 300px; height: 300px;" />var …

深入解析OrientDB:多模型数据库的技术优势与实际应用

OrientDB 是一款开源的多模型 NoSQL 数据库&#xff0c;融合了文档数据库、图数据库和对象数据库的特性。它不仅支持灵活的数据建模&#xff0c;还提供了高性能的查询能力&#xff0c;适用于社交网络、物联网、内容管理等场景。本文详细探讨 OrientDB 的核心特性、应用场景&…

STM32控制电机

初始化时钟&#xff1a;在 STM32 的程序中&#xff0c;初始化系统时钟&#xff0c;一般会使用 RCC&#xff08;Reset and Clock Control&#xff09;相关函数来配置时钟。例如&#xff0c;对于 STM32F103 系列&#xff0c;可能会使用 RCC_APB2PeriphClockCmd 函数来使能 GPIO 和…

(05)数字化转型之生产制造:从通常的离散制造到柔性化生产的全景指南

当今制造业正经历着前所未有的数字化变革&#xff0c;从传统的离散制造到流程制造&#xff0c;再到新兴的项目制造和柔性制造&#xff0c;各种生产模式都在加速向智能化方向演进。本文将系统性地介绍制造业生产管理的完整体系&#xff0c;为企业数字化转型提供全面的方法论和实…

龙虎榜——20250520

上证指数今天缩量向上&#xff0c;个股涨多跌少&#xff0c;大盘股和小盘股总体表现都还可以。 深证同样缩量上涨&#xff0c;向上补缺口的概率增大。 2025年5月20日龙虎榜行业方向分析 宠物经济&#xff08;消费升级政策催化&#xff09; • 代表标的&#xff1a;天元宠物、…

CVE-2022-22978源码分析与漏洞复现

漏洞概述 CVE-2022-22978 是 Spring Security 框架中的一个高危认证绕过漏洞&#xff0c;影响版本包括 Spring Security 5.5.x < 5.5.7、5.6.x < 5.6.4 及更早的不受支持版本。攻击者可通过构造包含换行符&#xff08;如 %0a&#xff09;的 URL 路径&#xff0c;绕过正则…

PostGIS实现栅格数据入库【raster2pgsql】

raster2pgsql使用与最佳实践 一、工具概述 raster2pgsql是PostGIS提供的命令行工具,用于将GDAL支持的栅格格式(如GeoTIFF、JPEG、PNG等)导入PostgreSQL数据库,支持批量加载、分块切片、创建空间索引及金字塔概览,是栅格数据入库的核心工具。 二、核心功能与典型用法 1…