禅与计算机 禅与计算机
首页
  • Java基础

    • 聊一聊java一些核心知识点
    • 聊聊java面向对象核心知识点
    • 聊聊Java中的异常
    • 聊聊Java中的常用类String
    • 万字长文带你细聊Java注解本质
    • 来聊聊Java的反射机制
    • 深入解析Java泛型的魅力与机制
    • Java集合框架深度解析与面试指南
    • Java常用集合类HashMap深度解析
    • LinkedHashMap源码到面试题的全解析
    • 深入解析CopyOnWriteArrayList的工作机制
    • Java基础IO总结
    • Java三大IO模型小结
    • Java BIO NIO AIO详解
    • Java进阶NIO之IO多路复用详解
    • Java8流式编程入门
    • 一文速通lambda与函数式编程
    • Java8函数式方法引用最佳实践
  • Java并发编程

    • Java并发编程基础小结
    • 深入理解Java中的final关键字
    • 浅谈Java并发安全发布技术
    • 浅谈Java并发编程中断的哲学
    • Java线程池知识点小结
    • 浅谈Java线程池中拒绝策略与流控的艺术
    • synchronized关键字使用指南
    • 深入源码解析synchronized关键字
    • 详解JUC包下的锁
    • 详解并发编程中的CAS原子类
    • LongAdder源码分析
    • AQS源码解析
    • 深入剖析Java并发编程中的死锁问题
    • Java并发容器总结
    • 详解Java并发编程volatile关键字
    • 并发编程ThreadLocal必知必会
    • CompletableFuture基础实践小结
    • CompletableFuture异步多任务最佳实践
    • 硬核详解FutureTask设计与实现
    • 线程池大小设置的底层逻辑与场景化方案
    • 来聊一个有趣的限流器RateLimiter
  • JVM相关

    • 从零开始掌握 JVM
    • JVM核心知识点小结
    • JVM指令集概览:基础与应用
    • JVM类加载器深度解析
    • JVM方法区深度解析
    • Java内存模型JMM详解
    • Java对象大小的精确计算方法
    • 逃逸分析在Java中的应用与优化
    • 从零开始理解JVM的JIT编译机制
    • G1垃圾回收器:原理详解与调优指南
    • JVM故障排查实战指南
    • JVM内存问题排错最佳实践
    • JVM内存溢出排查指南
    • 简明的Arthas使用教程
    • 简明的Arthas配置及基础运维教程
    • 基于Arthas Idea的JVM故障排查与指令生成
    • 基于arthas量化监控诊断java应用方法论与实践
    • 深入剖析arthas技术原理
  • 深入理解Spring框架

    • Spring 核心知识点全面解析
    • Spring核心功能IOC详解
    • Spring AOP 深度剖析与实践
    • Spring 三级缓存机制深度解析
    • 深入 Spring 源码,剖析设计模式的落地实践
    • 探索 Spring 事务的奥秘
    • 深入解析Spring Bean的生命周期管理
    • 解读 Spring Boot 核心知识点
    • Spring Boot 启动优化实战:1分钟到13秒的排查与优化之路
    • Spring Boot自动装配原理及实践
    • 一文快速上手Sharding-JDBC
    • sharding-jdbc如何实现分页查询
    • 基于DynamicDataSource整合分库分表框架Shardingsphere
  • 计算机组成原理

    • 计算机硬件知识小结
    • CPU核心知识点小结
    • 浅谈CPU流水线的艺术
    • 从Java程序员视角聊聊CPU缓存
    • CPU任务调度和伪共享问题小结
    • CPU MESI缓存一致性协议
    • CPU内存管理机制
    • 内存深度解析
    • 磁盘存储原理
    • 详解计算机启动步骤
    • CPU南北桥架构与发展史
    • CPU中断机制与硬件交互详解
  • 操作系统

    • 如何实现一个高性能服务器
    • Linux文件结构与文件权限
    • Linux常见压缩指令小结
    • Linux核心系统调用详解
    • Linux进程管理
    • Linux线程管理
    • 进程与线程深度解析
    • Linux进程间通信机制
    • 零拷贝技术原理与实践
    • CPU缓存一致性问题深度解析
    • IO任务与CPU调度艺术
  • 计算机网络

    • 网卡通信原理详解
    • 网卡数据包处理指南
    • 基于抓包详解TCP协议
  • 编码最佳实践

    • 浅谈现代软件工程TDD最佳实践
    • 浅谈TDD模式下并发程序设计与实现
    • 面向AI编程新范式Trae后端开发环境搭建与实践
    • 基于提示词工程的Redis签到功能开发实践
    • 基于Vibe Coding的Redis分页查询实现
    • 告别AI无效对话:资深工程师的提示词设计最佳实践
  • 实用技巧与配置

    • Mac常用快捷键与效率插件指南
    • Keynote技术科普短视频制作全攻略
  • 写作

    • 写好技术博客的5大核心原则:从认知科学到AI工具的全流程指南
  • 开发工具

    • IDEA配置详解与高效使用指南
  • Nodejs
  • 博客搭建
  • Redis

    • Redis核心知识小结
    • 解锁Redis发布订阅模式
    • 掌握Redis事务
    • Redis主从复制技术
    • Redis的哨兵模式详解
    • 深度剖析Redisson分布式锁
    • 详解redis单线程设计思路
    • 来聊聊Redis所实现的Reactor模型
    • Redis RDB持久化源码深度解析
    • 来聊聊redis的AOF写入
    • 来聊聊Redis持久化AOF管道通信的设计
    • 来聊聊redis集群数据迁移
    • Redis SDS动态字符串深度解析
    • 高效索引的秘密:redis跳表设计与实现
    • 聊聊redis中的字典设计与实现
  • MySQL

    • MySQL基础知识点小结
    • 解读MySQL 索引基础
    • MySQL 索引进阶指南
    • 解读MySQL Explain关键字
    • 探秘 MySQL 锁:原理与实践
    • 详解MySQL重做日志redolog
    • 详解undoLog在MySQL MVCC中的运用
    • MySQL二进制日志binlog核心知识点
    • MySQL高效插入数据的最佳实践
    • MySQL分页查询优化指南
    • MySQL流式查询的奥秘与应用解析
    • 来聊聊分库分表
    • 来聊聊大厂常用的分布式ID生成方案
  • ElasticSearch

    • 从Lucene到Elasticsearch:进化之路
    • ES 基础使用指南
    • ElasticSearch如何写入一篇文档
    • 深入剖析Elasticsearch文档读取原理
    • 聊聊ElasticSearch性能调优
    • Spring借助Easy-Es操作ES
  • Netty

    • 一文快速了解高性能网络通信框架Netty
    • Netty网络传输简记
    • 来聊聊Netty的ByteBuf
    • 来聊聊Netty消息发送的那些事
    • 解密Netty高性能之谜:NioEventLoop线程池阻塞分析
    • 详解Netty中的责任链Pipeline如何管理ChannelHandler
    • Netty Reactor模型常见知识点小结
    • Netty如何驾驭TCP流式传输?粘包拆包问题全解
    • Netty解码器源码解析
  • 消息队列

    • 一文快速入门消息队列
    • 消息队列RocketMQ入门指南
    • 基于RocketMQ实现分布式事务
    • RocketMQ容器化最佳实践
    • RocketMQ常见问题与深度解析
    • Kafka快速安装与使用指南
  • Nginx

    • Linux下的nginx安装
    • Nginx基础入门总结
    • Nginx核心指令小结
    • Nginx进程结构与核心模块初探
    • Nginx应用进阶HTTP核心模块配置
    • Nginx缓存及HTTPS配置小记
    • nginx高可用实践简记
    • Nginx性能优化
  • 微服务基础

    • 微服务基础知识小结
    • 分布式事务核心概念小结
    • OpenFeign核心知识小结
    • 微服务组件Gateway核心使用小结
    • 分布式事务Seata实践
    • 用 Docker Compose 完成 Seata 的整合部署
  • Nacos

    • Nacos服务注册原理全解析
    • Nacos服务订阅流程全解析
    • Nacos服务变更推送流程全解析
    • 深入解析SpringCloud负载均衡器Loadbalancer
    • Nacos源码环境搭建与调试指南
  • Seata

    • 深度剖析Seata源码
  • Docker部署

    • 一文快速掌握docker的理念和基本使用
    • 使用docker编排容器
    • 基于docker-compose部署微服务基本环境
    • 基于docker容器化部署微服务
    • Gateway全局异常处理及请求响应监控
    • Docker图形化界面工具Portainer最佳实践
  • Go基础

    • 一文带你速通Go语言基础语法
    • 一文快速掌握Go语言切片
    • 来聊聊go语言的hashMap
    • 一文速通go语言类型系统
    • 浅谈Go语言中的面向对象
    • go语言是如何实现协程的
    • 聊聊go语言中的GMP模型
    • 极简的go语言channel入门
    • 聊聊go语言基于epoll的网络并发实现
    • 写给Java开发的Go语言协程实践
  • mini-redis实战

    • 来聊聊我用go手写redis这件事
    • mini-redis如何解析处理客户端请求
    • 实现mini-redis字符串操作
    • 硬核复刻redis底层双向链表核心实现
    • 动手复刻redis之go语言下的字典的设计与落地
    • Go 语言下的 Redis 跳表设计与实现
    • Go 语言版 Redis 有序集合指令复刻探索
  • 项目编排

    • Spring脚手架创建简记
    • Spring脚手架集成分页插件
    • Spring脚手架集成校验框架
    • maven父子模块两种搭建方式简记
    • SpringBoot+Vue3前后端快速整合入门
    • 来聊聊Java项目分层规范
  • 场景设计

    • Java实现文件分片上传
    • 基于时间缓存优化浏览器轮询阻塞问题
    • 基于EasyExcel实现高效导出
    • 10亿数据高效插入MySQL最佳方案
    • 从开源框架中学习那些实用的位运算技巧
  • CI/CD

    • 基于NETAPP实现内网穿透
    • 基于Gitee实现Jenkins自动化部署SpringBoot项目
    • Jenkins离线安装部署教程简记
    • 基于Nexus搭建Maven私服基础入门
    • 基于内网的Jenkins整合gitlab综合方案简记
  • 监控方法论

    • SpringBoot集成Prometheus与Grafana监控
    • Java监控度量Micrometer全解析
    • 从 micrometer计量器角度快速上手promQL
    • 硬核安利一个监控告警开源项目Nightingale
  • Spring AI

    • Spring AI Alibaba深度实战:一文掌握智能体开发全流程
    • Spring AI Alibaba实战:JVM监控诊断Arthas Agent的工程化构建与最佳实践
  • 大模型评测

    • M2.7 真能打!我用两个真实场景测了测,结果有点意外
    • Qoder JetBrains插件评测:祖传代码重构与接口优化实战
关于
收藏
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

sharkchili

计算机禅修者
首页
  • Java基础

    • 聊一聊java一些核心知识点
    • 聊聊java面向对象核心知识点
    • 聊聊Java中的异常
    • 聊聊Java中的常用类String
    • 万字长文带你细聊Java注解本质
    • 来聊聊Java的反射机制
    • 深入解析Java泛型的魅力与机制
    • Java集合框架深度解析与面试指南
    • Java常用集合类HashMap深度解析
    • LinkedHashMap源码到面试题的全解析
    • 深入解析CopyOnWriteArrayList的工作机制
    • Java基础IO总结
    • Java三大IO模型小结
    • Java BIO NIO AIO详解
    • Java进阶NIO之IO多路复用详解
    • Java8流式编程入门
    • 一文速通lambda与函数式编程
    • Java8函数式方法引用最佳实践
  • Java并发编程

    • Java并发编程基础小结
    • 深入理解Java中的final关键字
    • 浅谈Java并发安全发布技术
    • 浅谈Java并发编程中断的哲学
    • Java线程池知识点小结
    • 浅谈Java线程池中拒绝策略与流控的艺术
    • synchronized关键字使用指南
    • 深入源码解析synchronized关键字
    • 详解JUC包下的锁
    • 详解并发编程中的CAS原子类
    • LongAdder源码分析
    • AQS源码解析
    • 深入剖析Java并发编程中的死锁问题
    • Java并发容器总结
    • 详解Java并发编程volatile关键字
    • 并发编程ThreadLocal必知必会
    • CompletableFuture基础实践小结
    • CompletableFuture异步多任务最佳实践
    • 硬核详解FutureTask设计与实现
    • 线程池大小设置的底层逻辑与场景化方案
    • 来聊一个有趣的限流器RateLimiter
  • JVM相关

    • 从零开始掌握 JVM
    • JVM核心知识点小结
    • JVM指令集概览:基础与应用
    • JVM类加载器深度解析
    • JVM方法区深度解析
    • Java内存模型JMM详解
    • Java对象大小的精确计算方法
    • 逃逸分析在Java中的应用与优化
    • 从零开始理解JVM的JIT编译机制
    • G1垃圾回收器:原理详解与调优指南
    • JVM故障排查实战指南
    • JVM内存问题排错最佳实践
    • JVM内存溢出排查指南
    • 简明的Arthas使用教程
    • 简明的Arthas配置及基础运维教程
    • 基于Arthas Idea的JVM故障排查与指令生成
    • 基于arthas量化监控诊断java应用方法论与实践
    • 深入剖析arthas技术原理
  • 深入理解Spring框架

    • Spring 核心知识点全面解析
    • Spring核心功能IOC详解
    • Spring AOP 深度剖析与实践
    • Spring 三级缓存机制深度解析
    • 深入 Spring 源码,剖析设计模式的落地实践
    • 探索 Spring 事务的奥秘
    • 深入解析Spring Bean的生命周期管理
    • 解读 Spring Boot 核心知识点
    • Spring Boot 启动优化实战:1分钟到13秒的排查与优化之路
    • Spring Boot自动装配原理及实践
    • 一文快速上手Sharding-JDBC
    • sharding-jdbc如何实现分页查询
    • 基于DynamicDataSource整合分库分表框架Shardingsphere
  • 计算机组成原理

    • 计算机硬件知识小结
    • CPU核心知识点小结
    • 浅谈CPU流水线的艺术
    • 从Java程序员视角聊聊CPU缓存
    • CPU任务调度和伪共享问题小结
    • CPU MESI缓存一致性协议
    • CPU内存管理机制
    • 内存深度解析
    • 磁盘存储原理
    • 详解计算机启动步骤
    • CPU南北桥架构与发展史
    • CPU中断机制与硬件交互详解
  • 操作系统

    • 如何实现一个高性能服务器
    • Linux文件结构与文件权限
    • Linux常见压缩指令小结
    • Linux核心系统调用详解
    • Linux进程管理
    • Linux线程管理
    • 进程与线程深度解析
    • Linux进程间通信机制
    • 零拷贝技术原理与实践
    • CPU缓存一致性问题深度解析
    • IO任务与CPU调度艺术
  • 计算机网络

    • 网卡通信原理详解
    • 网卡数据包处理指南
    • 基于抓包详解TCP协议
  • 编码最佳实践

    • 浅谈现代软件工程TDD最佳实践
    • 浅谈TDD模式下并发程序设计与实现
    • 面向AI编程新范式Trae后端开发环境搭建与实践
    • 基于提示词工程的Redis签到功能开发实践
    • 基于Vibe Coding的Redis分页查询实现
    • 告别AI无效对话:资深工程师的提示词设计最佳实践
  • 实用技巧与配置

    • Mac常用快捷键与效率插件指南
    • Keynote技术科普短视频制作全攻略
  • 写作

    • 写好技术博客的5大核心原则:从认知科学到AI工具的全流程指南
  • 开发工具

    • IDEA配置详解与高效使用指南
  • Nodejs
  • 博客搭建
  • Redis

    • Redis核心知识小结
    • 解锁Redis发布订阅模式
    • 掌握Redis事务
    • Redis主从复制技术
    • Redis的哨兵模式详解
    • 深度剖析Redisson分布式锁
    • 详解redis单线程设计思路
    • 来聊聊Redis所实现的Reactor模型
    • Redis RDB持久化源码深度解析
    • 来聊聊redis的AOF写入
    • 来聊聊Redis持久化AOF管道通信的设计
    • 来聊聊redis集群数据迁移
    • Redis SDS动态字符串深度解析
    • 高效索引的秘密:redis跳表设计与实现
    • 聊聊redis中的字典设计与实现
  • MySQL

    • MySQL基础知识点小结
    • 解读MySQL 索引基础
    • MySQL 索引进阶指南
    • 解读MySQL Explain关键字
    • 探秘 MySQL 锁:原理与实践
    • 详解MySQL重做日志redolog
    • 详解undoLog在MySQL MVCC中的运用
    • MySQL二进制日志binlog核心知识点
    • MySQL高效插入数据的最佳实践
    • MySQL分页查询优化指南
    • MySQL流式查询的奥秘与应用解析
    • 来聊聊分库分表
    • 来聊聊大厂常用的分布式ID生成方案
  • ElasticSearch

    • 从Lucene到Elasticsearch:进化之路
    • ES 基础使用指南
    • ElasticSearch如何写入一篇文档
    • 深入剖析Elasticsearch文档读取原理
    • 聊聊ElasticSearch性能调优
    • Spring借助Easy-Es操作ES
  • Netty

    • 一文快速了解高性能网络通信框架Netty
    • Netty网络传输简记
    • 来聊聊Netty的ByteBuf
    • 来聊聊Netty消息发送的那些事
    • 解密Netty高性能之谜:NioEventLoop线程池阻塞分析
    • 详解Netty中的责任链Pipeline如何管理ChannelHandler
    • Netty Reactor模型常见知识点小结
    • Netty如何驾驭TCP流式传输?粘包拆包问题全解
    • Netty解码器源码解析
  • 消息队列

    • 一文快速入门消息队列
    • 消息队列RocketMQ入门指南
    • 基于RocketMQ实现分布式事务
    • RocketMQ容器化最佳实践
    • RocketMQ常见问题与深度解析
    • Kafka快速安装与使用指南
  • Nginx

    • Linux下的nginx安装
    • Nginx基础入门总结
    • Nginx核心指令小结
    • Nginx进程结构与核心模块初探
    • Nginx应用进阶HTTP核心模块配置
    • Nginx缓存及HTTPS配置小记
    • nginx高可用实践简记
    • Nginx性能优化
  • 微服务基础

    • 微服务基础知识小结
    • 分布式事务核心概念小结
    • OpenFeign核心知识小结
    • 微服务组件Gateway核心使用小结
    • 分布式事务Seata实践
    • 用 Docker Compose 完成 Seata 的整合部署
  • Nacos

    • Nacos服务注册原理全解析
    • Nacos服务订阅流程全解析
    • Nacos服务变更推送流程全解析
    • 深入解析SpringCloud负载均衡器Loadbalancer
    • Nacos源码环境搭建与调试指南
  • Seata

    • 深度剖析Seata源码
  • Docker部署

    • 一文快速掌握docker的理念和基本使用
    • 使用docker编排容器
    • 基于docker-compose部署微服务基本环境
    • 基于docker容器化部署微服务
    • Gateway全局异常处理及请求响应监控
    • Docker图形化界面工具Portainer最佳实践
  • Go基础

    • 一文带你速通Go语言基础语法
    • 一文快速掌握Go语言切片
    • 来聊聊go语言的hashMap
    • 一文速通go语言类型系统
    • 浅谈Go语言中的面向对象
    • go语言是如何实现协程的
    • 聊聊go语言中的GMP模型
    • 极简的go语言channel入门
    • 聊聊go语言基于epoll的网络并发实现
    • 写给Java开发的Go语言协程实践
  • mini-redis实战

    • 来聊聊我用go手写redis这件事
    • mini-redis如何解析处理客户端请求
    • 实现mini-redis字符串操作
    • 硬核复刻redis底层双向链表核心实现
    • 动手复刻redis之go语言下的字典的设计与落地
    • Go 语言下的 Redis 跳表设计与实现
    • Go 语言版 Redis 有序集合指令复刻探索
  • 项目编排

    • Spring脚手架创建简记
    • Spring脚手架集成分页插件
    • Spring脚手架集成校验框架
    • maven父子模块两种搭建方式简记
    • SpringBoot+Vue3前后端快速整合入门
    • 来聊聊Java项目分层规范
  • 场景设计

    • Java实现文件分片上传
    • 基于时间缓存优化浏览器轮询阻塞问题
    • 基于EasyExcel实现高效导出
    • 10亿数据高效插入MySQL最佳方案
    • 从开源框架中学习那些实用的位运算技巧
  • CI/CD

    • 基于NETAPP实现内网穿透
    • 基于Gitee实现Jenkins自动化部署SpringBoot项目
    • Jenkins离线安装部署教程简记
    • 基于Nexus搭建Maven私服基础入门
    • 基于内网的Jenkins整合gitlab综合方案简记
  • 监控方法论

    • SpringBoot集成Prometheus与Grafana监控
    • Java监控度量Micrometer全解析
    • 从 micrometer计量器角度快速上手promQL
    • 硬核安利一个监控告警开源项目Nightingale
  • Spring AI

    • Spring AI Alibaba深度实战:一文掌握智能体开发全流程
    • Spring AI Alibaba实战:JVM监控诊断Arthas Agent的工程化构建与最佳实践
  • 大模型评测

    • M2.7 真能打!我用两个真实场景测了测,结果有点意外
    • Qoder JetBrains插件评测:祖传代码重构与接口优化实战
关于
收藏
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • Redis

    • Redis核心知识小结
    • Redis源码与实战剖析小结
    • Redis系列文章全汇总
    • 解锁Redis发布订阅模式:通过实践演示挖掘消息通信潜能
    • 掌握 Redis 事务,提升数据处理效率的必备秘籍
      • 写在文章开头
      • redis事务的基本概念
        • redis事务的基本概念
        • redis事务基础操作示例
      • 详解redis事务中的原子性
        • 组队时错误
        • 执行时错误
      • 详解redis事务中的乐观锁
        • 为什么redis需要事务
        • redis事务乐观锁使用示例
      • redis事务中的一些常见问题
        • 为什么redis不支持事务回滚
        • 如何理解redis的事务与ACID
        • Redis事务的其他实现方式吗
        • Redis事务三特性是什么?
        • 如何使用 Redis 事务?
        • 如何解决 Redis 事务的缺陷
      • 小结
      • 参考
    • 基于Jedis来探讨池化技术
    • Redis主从复制技术:理论基础、运行逻辑与应用场景
    • 聊聊Redis主从复制
    • Redis的哨兵模式详解
    • 深度剖析 Redisson 分布式锁:原理、实现与应用实践
    • 来聊聊Redis中的字符串对象的设计
    • 详解redis单线程设计思路
    • 基于Gdb快速上手调试Redis
    • 聊聊redis中的有序集合
    • 来聊聊redis文件事件驱动的设计
    • 如何理解redis是单线程的
    • 来聊聊Redis所实现的Reactor模型
    • 来聊聊Redis客户端的概念
    • 来聊聊redis数据库的设计与实现
    • 来聊聊Redis定期删除策略的设计与实现
    • 聊聊Redis中缓存淘汰算法的实现
    • Redis RDB持久化源码深度解析:从原理到实现
    • 一文读懂Redis RDB持久化:策略、配置与应用
    • 来聊聊redis的AOF写入
    • 来聊聊Redis的AOF重写机制
    • 来聊聊Redis持久化AOF管道通信的设计
    • Redis如何高效实现定时任务
    • 以从节点的角度看看Redis主从复制的实现
    • Redis哨兵是如何完成初始化的
    • 聊聊Redis哨兵选举与故障转移的实现
    • 来聊聊Redis哨兵如何主观认定下线
    • 来聊聊redis的发布订阅设计与实现
    • 来聊聊去中心化Redis集群节点如何完成通信
    • redis集群中如何处理非本节点的slot
    • 来聊聊redis集群数据迁移
    • 硬核详解redis客户端指令与服务端传输协议RESP
    • 从redis源码了解双向链表的设计与实现
    • 能不能给我讲讲redis中的列表
    • 聊聊redis中的字典设计与实现
    • 聊聊redis字典指令操作
    • 高效索引的秘密:redis跳表设计与实现
    • 探索数据结构之美——有序集合的内部机制
    • Redis SDS动态字符串深度解析
    • Redis核心数据结构字典操作实践与解析
    • Redis持久化技术AOF要点与详细解答
    • Redisson全面解析从使用方法到工作原理的深度探索
    • 基于VSCode调试Redis源码指南
    • Redis持久化技术AOF要点与详细解答(2)
  • MySQL

  • ElasticSearch

  • StarRocks

  • 数据库
  • Redis
sharkchili
2022-12-14
目录

掌握 Redis 事务,提升数据处理效率的必备秘籍

# 写在文章开头

在实际的软件开发项目中,我们经常会遇到需要对数据进行一系列连续操作的情况,而且这些操作必须作为一个整体要么全部成功,要么全部失败,以保证数据的一致性。比如在电商系统中,下单、扣库存、记录订单信息等操作需要作为一个不可分割的整体来执行。Redis作为一款常用的数据库,其事务功能就为解决这类问题提供了有力的支持。那么,如何在项目中正确、高效地使用Redis事务呢?

Hi,我是 sharkChili ,是个不断在硬核技术上作死的技术人,是 CSDN的博客专家 ,也是开源项目 Java Guide 的维护者之一,熟悉 Java 也会一点 Go ,偶尔也会在 C源码 边缘徘徊。写过很多有意思的技术博客,也还在研究并输出技术的路上,希望我的文章对你有帮助,非常欢迎你关注我的公众号: 写代码的SharkChili 。

同时也非常欢迎你star我的开源项目mini-redis:https://github.com/shark-ctrl/mini-redis (opens new window)

因为近期收到很多读者的私信,所以也专门创建了一个交流群,感兴趣的读者可以通过上方的公众号获取笔者的联系方式完成好友添加,点击备注 “加群” 即可和笔者和笔者的朋友们进行深入交流。

# redis事务的基本概念

# redis事务的基本概念

redis的事务是一个单独隔离的操作,它会将一系列指令按需排队并顺序执行,期间不会被其他客户端的指令插队,所以redis事务是保证组合命令的原子性。

redis的事务指令有3个关键字,分别是:

  1. multi:开启事务
  2. exec:执行事务
  3. discard:取消事务

通过multi,当前客户端就会开启事务,后续用户键入的都指令都会保证到队列中暂不执行,当用户键入exec后,这些指令都会按顺序执行。 需要注意的是,若开启multi后输入若干指令,客户端输入discard,则之前的指令通通取消执行。

# redis事务基础操作示例

如上所示,事务本质就是开启、入队、提交,接下来我们就来简单演示一下,打开客户端首先开启事务:

# 开启事务
127.0.0.1:6379> MULTI
OK
1
2
3

然后将需要执行的操作提交:

# 将两个指令组队
127.0.0.1:6379(TX)> set k1 v1
QUEUED
127.0.0.1:6379(TX)> set k2 v2
QUEUED
1
2
3
4
5

完成后,我们就可以通过exec指令提交并执行:

# 执行两个指令
127.0.0.1:6379(TX)> EXEC
1) OK
2) OK
1
2
3
4

最后查看执行验证一下结果:

# 查看执行结果
127.0.0.1:6379> keys *
1) "k1"
2) "k2"

1
2
3
4
5

# 详解redis事务中的原子性

# 组队时错误

redis事务中的错误分别以下两种:

  1. 组队时错误
  2. 执行命令时错误

我们先来说说组队时错误的指令,上文我们已经说过,redis事务开启后提交的指令都会存到队列中,这也就意味着在指令提交阶段redis是可以感知到语法上的错误,所以在组队时错误,redis一旦感知到错误,这些指令都不会执行:

# 开启事务
127.0.0.1:6379> MULTI
OK
# 指令入队
127.0.0.1:6379(TX)> set k1 v1
QUEUED
127.0.0.1:6379(TX)> set k2 v2
QUEUED
127.0.0.1:6379(TX)> set k33
(error) ERR wrong number of arguments for 'set' command
127.0.0.1:6379(TX)> set k4 v4
QUEUED
# 执行指令
127.0.0.1:6379(TX)> exec
(error) EXECABORT Transaction discarded because of previous errors.
# 指令并没有被执行
127.0.0.1:6379> keys *
(empty array)
127.0.0.1:6379>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

这一点我们也可以从源码的角度分析,redis会为每一个redis客户端分配一个结构体维护其内部信息,这其中flag字段就代表着客户端各种状态标识,这其中低3位就表示客户端是否开启事务标识,如果1就代表开启,反之代表未开启:

对此我们也给出这段结构体定义,即位于redis.h的redisClient 结构体定义:

typedef struct redisClient {
//......
    int argc;
    robj **argv;
    //......
    //标识是否被设置为slave、或者监控slave的、或者键入过multi开启事务
    int flags; /* REDIS_SLAVE | REDIS_MONITOR | REDIS_MULTI ... */
    //......
}
1
2
3
4
5
6
7
8
9

当redis开启事务需要multi指令,客户端键入该指令之后,redis首先就会通过按位与判断这个二进制为是否被标识为1,若没有则直接位运算为1开启事务。后续如果再次键入multi则会直接抛出嵌套事务异常告知客户端不可重复调用multi指令:

对应的我们给出multi指令的源码实现multiCommand,逻辑和笔者说明的一致解:

void multiCommand(redisClient *c) {
    //REDIS_MULTI值为1<<3 如果按位与发现当前客户端已经被标识为开启事务,则直接跑错事务不可嵌套的异常
    if (c->flags & REDIS_MULTI) {
        addReplyError(c,"MULTI calls can not be nested");
        return;
    }
    //REDIS_MULTI值为1<<3 通过 | 符号将低3位标识为1,意为开启事务
    c->flags |= REDIS_MULTI;
    addReply(c,shared.ok);
}
1
2
3
4
5
6
7
8
9
10

开启事务后,用户的指令提交处理都会走到公用处理函数processCommand,一旦感知到某条指令处理异常,redis就会将客户端标识flag标记为脏事务REDIS_DIRTY_EXEC。 基于该标记,执行exec提交事务时就可以感知指令是否在组队时存在异常,如果存在异常则直接取消所有指令的执行保证组队时事务的原子性:

对应我们给出所有指令提交前的通用逻辑函数processCommand,可以看到如果服务端感知到指令的指令参数不一致等异常就会调用flagTransaction将事务标记为脏:

int processCommand(redisClient *c) {
   	//.......
    c->cmd = c->lastcmd = lookupCommand(c->argv[0]->ptr);
    if (!c->cmd) {
     //......
    } else if ((c->cmd->arity > 0 && c->cmd->arity != c->argc) ||
               (c->argc < -c->cmd->arity)) {//检查参数数和命令表配置是否一致
        //如果发现不一致则将客户端flags标识标记上REDIS_DIRTY_EXEC标识当前事务是脏事务       
        flagTransaction(c);
        addReplyErrorFormat(c,"wrong number of arguments for '%s' command",
            c->cmd->name);
        return REDIS_OK;
    }
    //......
}


void flagTransaction(redisClient *c) {
    //如果开启事务则将flags标记上REDIS_DIRTY_EXEC,标识当前事务已脏
    if (c->flags & REDIS_MULTI)
        c->flags |= REDIS_DIRTY_EXEC;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

有了上述的基础,我们执行的exec就会通过判断flags查看是否被标记为REDIS_DIRTY_EXEC ,如果是则调用discardTransaction也就是discard清除队列中的指令不执行:

void execCommand(redisClient *c) {
   //......
    //如果发现标识标记为REDIS_DIRTY_EXEC,则调用 discardTransaction释放掉事务队列的指令不执行
    if (c->flags & (REDIS_DIRTY_CAS|REDIS_DIRTY_EXEC)) {
        addReply(c, c->flags & REDIS_DIRTY_EXEC ? shared.execaborterr :
                                                  shared.nullmultibulk);
        discardTransaction(c);
        goto handle_monitor;
    }

   
	//......
}
1
2
3
4
5
6
7
8
9
10
11
12
13

来小结一下,redis组队时异常回滚的底层实现:

  1. multi开启事务
  2. 提交指令,如果发现指令异常则将当前客户端事务标记为脏事务
  3. 调用exec时判断客户端标识,如果包含脏标记则清除事务队列中的指令不执行

# 执行时错误

有了上述基础我们就很好理解执行时错误了,执行时错误比较特殊,他在按序处理所有指令,即时遇到错误就按正常流程处理继续执行下去,如下示例所示,可以看到我们将k1对应的value是字符串类型,第二条指令执行错误后,k2还是正常设置进去了:

# 开启事务
127.0.0.1:6379> MULTI
OK
# 设置字符串k1 v1
127.0.0.1:6379(TX)> set k1 v1
QUEUED

# 设置v1进行自增,此时redis无法感知到这个异常
127.0.0.1:6379(TX)> INCR k1
QUEUED
# 正常键值对设置
127.0.0.1:6379(TX)> set k2 v2
QUEUED
# 提交执行,1、3指令执行成功
127.0.0.1:6379(TX)> EXEC
1) OK
2) (error) ERR value is not an integer or out of range
3) OK
# 即使指令2失败,指令3还是正常提交
127.0.0.1:6379> keys *
1) "k1"
2) "k2"
127.0.0.1:6379>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

# 详解redis事务中的乐观锁

# 为什么redis需要事务

通过redis事务解决需要高性能且需要保证原子性的符合指令操作,最经典的就是秒杀场景,如下图,假设一个秒杀活动中有3个用户,同时通过get指令发现库存剩下1,全部通过原子扣减指令进行扣减,导致超卖:

常见的解决方案有悲观锁和乐观锁,悲观锁(Pessimistic Lock)的原理是认为自己操作的数据很可能会被他人修改,所以对临界资源操作都持有悲观的态度,每次进行操作前都会对数据上锁保证互斥,常见的关系型数据库MySQL的行锁、表锁等都是基于这种锁机制:

我们再来说说乐观锁(Optimistic Lock),该锁的总是乐观的认为自己操作的数据不会被他人修改,进行修改操作时不会针对临界资源上锁,而是修改的时候判断一下当前去数据版本号和修改的数据是否一致,通过比对版本号是否一致判断是否被人修改,只要版本号一致当前线程修改操作就会生效,redis中的watch关键字和jdk下的JUC包下的原子类就是采用这种工作机制:

# redis事务乐观锁使用示例

这里我们就演示一下redis乐观锁的实现,原理比较简单,通过watch指令监听事务操作要操作的一个或者多个key值,当用户提交修改事务时,watch指令没有检测到key发生变化,则提交成功。

为方便演示,我们假设需要用事务操作名称为key的数据,我们首先初始化一下这个键值对:

# 设置key值
127.0.0.1:6379> set key 10
OK
1
2
3

然后开始watch指令监听这个key:

# 监听key
127.0.0.1:6379> WATCH key
OK
1
2
3

此时我们就可以开启事务提交要执行的操作:

# 开启事务
127.0.0.1:6379> MULTI
OK
1
2
3

同理我们在这时候起一个客户端2同样执行watch和multi操作:

# 监听key
127.0.0.1:6379> WATCH key
OK
# 开启事务
127.0.0.1:6379> MULTI
OK
1
2
3
4
5
6

此时我们回到客户端1执行修改操作,可以看到因为watch到key没有发生改变,修改操作成功:

# 指令加入队列
127.0.0.1:6379(TX)> INCR key
QUEUED

# 执行指令,可以看到执行成功,修改了一条数据,值被更新为11
127.0.0.1:6379(TX)> EXEC
1) (integer) 11
1
2
3
4
5
6
7

此时我们回到客户端2提交指令并提交,可以看到提交结果失败了,返回nil:

127.0.0.1:6379(TX)> INCR key
QUEUED
127.0.0.1:6379(TX)> exec
(nil)
1
2
3
4

这里我们也从源码的角度解释一下redis对于watch乐观锁的实现,如上操作,当我们客户端键入watch指令时监控key时,redis就会将当前客户端的信息挂到一个watched_keys的字典中,用key作为键,客户端信息作为value追加到这个key的链表中。

我们客户端1提交时,因为之前没有客户端进行修改,所以成功提交修改操作,并将watched_keys中监听key的所有客户端的flags标识为已被CAS修改即枚举变量REDIS_DIRTY_CAS数值为1<<5。

然后客户端2进行修改操作时,看到自己的flags被修改为REDIS_DIRTY_CAS就知道了当前key被人修改了,所以乐观修改操作失败:

对应源码如下,当客户端1执行exec时发现监听的key没有被人修改,执行incr操作之后,就会走到下面这个方法touchWatchedKey将watched_keys中监听key的客户端标识标记为REDIS_DIRTY_CAS,告知当前这个key已被我们修改:

void touchWatchedKey(redisDb *db, robj *key) {
  	//......
    //从watched_keys找到监听当前key的所有客户端
    clients = dictFetchValue(db->watched_keys, key);
   //......
    //遍历订阅这个key的所有客户端
    listRewind(clients,&li);
    while((ln = listNext(&li))) {
        redisClient *c = listNodeValue(ln);
        //标识为REDIS_DIRTY_CAS
        c->flags |= REDIS_DIRTY_CAS;
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13

所以当客户端2的执行exec时,调用来到了execCommand,当他发现自己的标识即flags字段被客户端1标记为REDIS_DIRTY_CAS,就知道当前key被人修改了,于是就执行discard取消执行当前指令:


void execCommand(redisClient *c) {
  
 //......
    //如果发现标识标记为REDIS_DIRTY_EXEC或REDIS_DIRTY_CAS(当前watch的key被人修改),则调用 discardTransaction释放掉事务队列的指令不执行
    if (c->flags & (REDIS_DIRTY_CAS|REDIS_DIRTY_EXEC)) {
        addReply(c, c->flags & REDIS_DIRTY_EXEC ? shared.execaborterr :
        //执行discard操作清除当前客户端提交的执行,且不执行                                         shared.nullmultibulk);
        discardTransaction(c);
        goto handle_monitor;
    }

 //......
1
2
3
4
5
6
7
8
9
10
11
12
13

# redis事务中的一些常见问题

# 为什么redis不支持事务回滚

redis实际上是支持事务回滚的,只不过这种回滚是仅仅支持组队时的异常,只有组队时感知到指令错误,redis服务端才会标记异常,后续执行exec时就会将提交队列的指令清除且不执行,由此原子性。

# 如何理解redis的事务与ACID

  1. 原子性: redis设计者认为他们是支持原子性的,因为原子性的概念是,所有指令要么全部执行,要么全部不执行,只要客户端提交的指令能够在组队阶段被感知,它就能做到指令操作的原子性。
  2. 一致性: 针对数据的一致性,我们从3种情况进行讨论:

1. 组队阶段:如果在事务组队阶段感知到异常,redis会主动丢弃事务中的指令且不执行,可以保证一致性。
2. 执行时异常:在事务执行阶段出现异常,redis还是会顺序执行后续的指令,一致性就会被破坏
3. 事务提交前redis宕机:如果开启了rdb或者aof持久化机制,可以在服务重启时重新加载提交到队列中的数据,保证一致性。
1
2
3
4
  1. 隔离性: 隔离性要求避免所有的客户端事务操作并发交叉执行时导致数据不一致问题,如上乐观锁的说明,我们可以通过watch关键字监听key的变化保证事务提交时感知到其他客户端的修改,如果发生修改就不提交事务,由此避免隔离性遭到破坏。
  2. 持久性: 持久性的定义为事务处理结束后,对数据的修改就是永久的,即便系统故障也不会丢失。),考虑到性能问题,redis无论rdb还是aof都是异步持久化,所以并不能保证持久性。

# Redis事务的其他实现方式吗

基于lua脚本可以保证redis指令一次性执按顺序执行完成,并且不会被其他客户端打断,但是这种方式却无法实现事务回滚,所以我们可以需要在lua脚本的实现上进行响应的处理。

# Redis事务三特性是什么?

  1. 单独的隔离操作:事务中的命令都会序列化并且按序执行,执行过程中不会被其他客户端的指令打断。
  2. 没有隔离级别的概念: 事务提交前所有指令都不会被执行。
  3. 组队阶段原子性:上文示例已经演示过,执行时出错某段指令,事务过程中的指令仍然会生效。

# 如何使用 Redis 事务?

Redis 可以通过 MULTI,EXEC,DISCARD 和 WATCH 等命令来实现事务(transaction)功能。

# 如何解决 Redis 事务的缺陷

从上文我们看出基于redis事务进行秒杀方面的需求时会出现库存遗留问题,这就是redis事务乐观锁机制的缺陷。 为了保证所有事务都能一次性的执行,我们可以使用lua脚本更快(lua脚本可以轻易调用C语言库函数以及被C语言直接调用)、更有效(基于lua脚本可以保证指令一次性被执行不会被其他线程打断),但是这种方案不支持回滚。

# 小结

本文从redis事务和底层源码两个角度深入分析了其工作机制和使用注意事项,希望对你有帮助。 我是 sharkchili ,CSDN Java 领域博客专家,mini-redis的作者,我想写一些有意思的东西,希望对你有帮助,如果你想实时收到我写的硬核的文章也欢迎你关注我的公众号: 写代码的SharkChili 。

同时也非常欢迎你star我的开源项目mini-redis:https://github.com/shark-ctrl/mini-redis (opens new window)

因为近期收到很多读者的私信,所以也专门创建了一个交流群,感兴趣的读者可以通过上方的公众号获取笔者的联系方式完成好友添加,点击备注 “加群” 即可和笔者和笔者的朋友们进行深入交流。

# 参考

Redis进阶 - 事务:Redis事务详解:https://www.pdai.tech/md/db/nosql-redis/db-redis-x-trans.html#cas操作实现乐观锁 (opens new window)

Redis常见面试题总结(下):https://javaguide.cn/database/redis/redis-questions-02.html#如何解决-redis-事务的缺陷 (opens new window)

Redis的watch机制详解:https://blog.csdn.net/jkzyx123/article/details/142053278 (opens new window)

取二进制数中特定第几的位置:https://blog.csdn.net/LOUTINI/article/details/81052744 (opens new window)

Redis实现库存扣减操作:https://blog.csdn.net/weixin_40663800/article/details/102902899 (opens new window)

悲观锁和乐观锁的区别:https://blog.csdn.net/weixin_50651363/article/details/119747515 (opens new window)

acid:https://baike.baidu.com/item/ACID/10738 (opens new window)

《Redis核心技术与实战》

编辑 (opens new window)
上次更新: 2026/03/26, 01:05:31
解锁Redis发布订阅模式:通过实践演示挖掘消息通信潜能
基于Jedis来探讨池化技术

← 解锁Redis发布订阅模式:通过实践演示挖掘消息通信潜能 基于Jedis来探讨池化技术→

最近更新
01
基于EasyExcel实现高效导出
03-25
02
从开源框架中学习那些实用的位运算技巧
03-25
03
浅谈分布式架构设计思想和常见优化手段
03-25
更多文章>
Theme by Vdoing | Copyright © 2025-2026 Evan Xu | MIT License | 桂ICP备2024034950号 | 桂公网安备45142202000030
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式
×
×