分布式锁和事务注解结合使用

news2025/5/18 1:09:20

在这里插入图片描述
在分布式系统中,事务注解(如 @Transactional)与分布式锁的结合使用是保障数据一致性和高并发安全的核心手段。以下是两者的协同使用场景及技术实现要点:


一、事务注解的局限性及分布式锁的互补性

维度事务注解(@Transactional)分布式锁
作用范围单数据库事务(ACID)跨服务、跨数据库的全局资源协调
适用场景转账、库存扣减等单点数据操作秒杀、集群任务调度、配置更新等分布式场景
典型问题无法解决跨服务的事务隔离(如订单创建与物流系统协同)防止重复提交、资源超卖、多节点并发冲突

案例:用户支付时需同时更新订单状态(MySQL)和发送消息(Kafka),仅用 @Transactional 无法保证两者原子性,需配合分布式锁协调跨系统操作。


二、注解化分布式锁的实现方案

1. 核心组件

  • 注解定义:自定义 @DistributedLock 注解,支持动态参数(如 keys = {"#orderId}"
  • AOP切面:通过 @Around 拦截方法,在事务执行前后加锁/解锁
  • 锁服务:基于 Redisson 或 RedisTemplate 实现原子操作

2. 代码示例(Spring Boot + Redisson)

@Aspect
@Component
public class DistributedLockAspect {
    @Autowired
    private RedissonClient redissonClient;

    @Around("@annotation(distributedLock)")
    public Object lock(ProceedingJoinPoint pjp, DistributedLock distributedLock) throws Throwable {
        String lockKey = buildLockKey(pjp, distributedLock); // 动态生成Key(如:order:1001)
        RLock lock = redissonClient.getLock(lockKey);
        try {
            if (lock.tryLock(3, 30, TimeUnit.SECONDS)) { // 等待3秒,锁持有30秒
                return pjp.proceed(); // 执行事务方法
            } else {
                throw new RuntimeException("获取锁失败");
            }
        } finally {
            if (lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
    }
}

3. 动态Key生成策略

  • 参数注入:使用 SpEL 表达式解析方法参数
    @DistributedLock(prefix="order", keys={"#order.id", "#user.id"})
    public void createOrder(Order order, User user) { ... }
    
  • 组合Key:生成类似 order:1001:u2025 的唯一标识,避免锁粒度过粗或过细。

三、典型场景及最佳实践

1. 高并发下单场景

  • 问题:用户多次点击导致重复订单
  • 解决方案
    @DistributedLock(prefix = "order_lock", keys = {"#userId"})
    @Transactional
    public Order createOrder(Long userId, Item item) {
        // 检查库存 → 扣减库存 → 生成订单(事务内操作)
    }
    
    • 锁策略:以用户ID为粒度,限制同一用户5秒内仅允许一次下单

2. 定时任务防重复执行

  • 问题:多节点同时触发报表生成导致数据错乱
  • 解决方案
    /**
     * 0 0 12 * * ?:每天中午 12 点执行。
     * 0 0/5 * * * ?:每 5 分钟执行一次。
     * 0 0 8-18 ? * MON-FRI:周一至周五的 8 点到 18 点之间每小时执行一次。
     */
    @Scheduled(cron = "0 0 12 * * ?")
    @DistributedLock(prefix = "report_task", expire = 3600)
    public void generateDailyReport() {
        // 跨数据库汇总数据 → 写入ES(非事务操作仍需锁协调)
    }
    
    • 锁超时:设置1小时过期时间,避免任务中断导致死锁

3. 分布式事务补偿

  • 问题:跨服务事务部分失败后的数据回滚
  • 方案组合
    1. 使用 @DistributedLock 锁定主资源

    2. @Transactional 执行本地事务

    3. 通过 TCCSaga 模式实现跨服务补偿

      对于某些分布式事务场景,流程多、流程长、还可能要调用其它公司的服务。特别是对于不可控的服务(其他公司的服务),这些服务无法遵循 TCC 开发模式,导致TCC模式的开发成本增高,且使用TCC模式会影响并发性能。
      鉴于上述业务场景的分布式事务处理,提出了Saga分布式处理模式。Saga是一种“长事务的解决方案”,更适合于“业务流程长、业务流程多”的场景。特别是针对参与事务的服务是遗留系统服务,此类服务无法提供TCC模式下的三个接口,就可以采用Saga模式。


四、风险规避与性能优化

1. 死锁预防

  • 自动续期:Redisson 看门狗机制(默认续期30秒)
  • 超时兜底:Redis Key 设置 TTL(如 expire=30s
  • 熔断降级:锁获取失败时快速返回,避免线程阻塞

2. 性能优化

  • 本地缓存:结合 Caffeine 实现二级锁(减少80% Redis请求)

  • 锁分段:将热点资源拆分为多个锁(如商品库存按ID取模分10段)

  • 无锁化改造:对非强一致性场景使用 版本号CRDT 冲突-free 数据结构

    • CRDT(conflict-freereplicateddatatype)无冲突复制数据类型,是一种可以在网络中的多台计算机上复制的数据结构,副本可以独立和并行地更新,不需要在副本之间进行协调,并保证不会有冲突发生。
    • CRDT常被用在协作软件上,例如多个用户需要共同编辑/读取共享的文档、数据库或状态的场景。
    • 在数据库软件,文本编辑软件,聊天软件等都可以用到它。

3. 监控指标

指标阈值工具
锁等待时间(LockWaitTime)< 100msPrometheus + Grafana
锁持有时间(LockHoldTime)< 1sRedisson Metrics
锁竞争失败率(LockFailRate)< 0.1%ELK 日志分析

五、选型对比

方案适用场景TPS强一致性开发成本
Redisson + 注解电商、金融等高并发50万+
ZooKeeper 临时节点配置管理、选主1万
数据库乐观锁 + 事务注解低频强事务(如ERP)5千
ETCD 租约机制云原生/K8s环境10万

总结

事务注解与分布式锁的协同实现了 本地事务原子性全局资源协调 的双重保障。在云原生架构下,推荐采用 Redisson注解化锁 + Seata事务 的组合方案,既能通过声明式编程降低开发复杂度,又能支撑百万级 QPS 的分布式场景。关键是通过合理的锁粒度控制和监控体系,在一致性、性能、复杂度之间取得平衡。

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

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

相关文章

全国产压力传感器常见的故障有哪些?

全国产压力传感器常见的故障如哪些呢&#xff1f;来和武汉利又德的小编一起了解一下&#xff0c;主要包括以下几类&#xff1a; 零点漂移 表现&#xff1a;在没有施加压力或处于初始状态时&#xff0c;传感器的输出值偏离了设定的零点。例如&#xff0c;压力为零时&#xff0c…

使用nhdeep档案目录打印工具生成干部人事档案目录打印文件

打开nhdeep档案目录打印工具&#xff0c;在左侧的模版列表中选中"干部人事档案目录"模版。 然后点击右下角“批量导入行”按钮&#xff0c;选择事先准备好的人事目录数据excel文件完成导入。 人事目录数据excel文件的结构和内容如下&#xff1a; 导入完成后&#xf…

工作记录 2015-08-24

工作记录 2015-08-24 序号 工作 相关人员 1 更新76.19的D:\FNEHRRD&#xff0c;更新的差不多了&#xff0c;还在测试中。具体情况见附件。 郝 识别引擎监控 Ps (iCDA LOG :剔除了204篇ASG_BLANK之后的结果): LOG_File 20150823.txt BLANK_CDA/ALL 102/947 (10.8%) TIME…

在 Dev-C++中编译运行GUI 程序介绍(三)有趣示例一组

在 Dev-C中编译运行GUI程序介绍&#xff08;三&#xff09;有趣示例一组 前期见 在 Dev-C中编译运行GUI 程序介绍&#xff08;一&#xff09;基础 https://blog.csdn.net/cnds123/article/details/147019078 在 Dev-C中编译运行GUI 程序介绍&#xff08;二&#xff09;示例&a…

Compose 适配 - 响应式排版 自适应布局

一、概念 基于可用空间而非设备类型来设计自适应布局&#xff0c;实现设备无关性和动态适配性&#xff0c;避免硬编码&#xff0c;以不同形态布局更好的展示内容。 二、区分可用空间 WindowSizeClasses 传统根据屏幕大小和方向做适配的方式已不再适用&#xff0c;APP的显示方式…

光储充智能协调控制系统的设计与应用研究

摘要 随着化石能源枯竭与环境污染问题加剧&#xff0c;构建高效、稳定的新能源系统成为能源转型的关键。本文针对光伏发电间歇性、储能系统充放电效率及充电桩动态负荷分配等技术挑战&#xff0c;提出一种基于智能协调管理的光储充一体化解决方案。通过多源数据融合与优化控制算…

UE4 踩坑记录

1、Using git status to determine working set for adaptive non-unity build 我删除了一个没用的资源&#xff0c;结果就报这个错&#xff0c;原因就是这条命令导致的&#xff0c; 如果这个项目是git项目&#xff0c; ue编译时会优先通过 git status检查哪些文件被修改&#…

C语言超详细指针知识(一)

通过前面一段学习C语言的学习&#xff0c;我们了解了数组&#xff0c;函数&#xff0c;操作符等相关知识&#xff0c;今天我们将要进行指针学习&#xff0c;这是C语言中较难的一个部分&#xff0c;我将带你由浅入深慢慢学习。 1.内存与地址 在正式学习指针前&#xff0c;我们首…

《算法笔记》3.3小节——入门模拟->图形输出

1036 跟奥巴马一起编程 #include <iostream> #include <cmath> using namespace std;int main() {int n,m;char c;cin>>n>>c;for (int i 0; i < n; i) {cout<<c;}cout<<endl;m round(1.0*n/2)-2;//round里面不能直接写n/2&#xff0c;…

【深入浅出 Git】:从入门到精通

这篇文章介绍下版本控制器。 【深入浅出 Git】&#xff1a;从入门到精通 Git是什么Git的安装Git的基本操作建立本地仓库配置本地仓库认识工作区、暂存区、版本库的概念添加文件添加文件到暂存区提交文件到版本库提交文件演示 理解.git目录中的文件HEAD指针与暂存区objects对象 …

在gitee上创建仓库——拉取到本地---添加文件---提交

2025/04/11/yrx0203 1-创建仓库 2-填写信息 3-创建完成后把仓库地址复制下来 4-在电脑上创建1个空的文件夹&#xff0c;进入这个文件夹&#xff0c;鼠标右击打开git bash 5-粘贴刚才复制的仓库的地址&#xff0c;回车 这样仓库就被拉取完成了 6-把本地的这个文件夹初始化…

小刚说C语言刷题——第21讲 一维数组

在日常生活中&#xff0c;我们经常输入一组数据。例如输入一个班30名学生的语文成绩&#xff0c;或者输入一组商品的价格。这个时候&#xff0c;我们如何输入一组类型相同的数据呢&#xff1f;这里我们就要用到数组。 1.数组的概念 所谓数组就是一组相同类型数据的集合。数组中…

芯片同时具备Wi-Fi、蓝牙、Zigbee,MAC地址会打架吗?

目录 【MAC 地址简介】 【MAC、Wi-Fi MAC、Bluetooth MAC的关系】 【以乐鑫ESP32-C6为例分析MAC】 【MAC 地址简介】 MAC&#xff08;Media Access Control&#xff09;地址是设备的物理地址&#xff0c;在全球范围内唯一标识每个网络接口。它是一个 48 比特&#xff08;6 字…

基于风力水力和蓄电池的低频率差联合发电系统simulink建模与仿真

目录 1.课题概述 2.系统仿真结果 3.核心程序与模型 4.系统原理简介 4.1 风力发电 4.2 风力发电 4.3 蓄电池原理 4.4 蓄电池对系统稳定性分析 5.完整工程文件 1.课题概述 基于风力水力和蓄电池的低频率差联合发电系统simulink建模与仿真。模型包括风力发电模块&#xf…

Harmony实战之简易计算器

前言 臭宝们&#xff0c;在学会上一节的基础知识之后&#xff0c;我们来实战一下。 预备知识 我们需要用到的知识点有&#xff1a; Column组件Row组件Link装饰器button组件TextInput组件State装饰器 最终效果图 代码实现 index页面(首页) /** * program: * * descriptio…

Spring MVC 国际化机制详解(MessageSource 接口体系)

Spring MVC 国际化机制详解&#xff08;MessageSource 接口体系&#xff09; 1. 核心接口与实现类详解 接口/类名描述功能特性适用场景MessageSource核心接口&#xff0c;定义消息解析能力支持参数化消息&#xff08;如{0}占位符&#xff09;所有国际化场景的基础接口Resource…

文件IO5(JPEG图像原理与应用)

JPEG图像原理与应用 ⦁ 基本概念 JPEG&#xff08;Joint Photographic Experts Group&#xff09;指的是联合图像专家组&#xff0c;是国际标准化组织ISO制订并于1992年发布的一种面向连续色调静止图像的压缩编码标准&#xff0c;所以也被称为JPEG标准。 同样&#xff0c;JP…

P8682 [蓝桥杯 2019 省 B] 等差数列

题目描述 思路 让求包含这n个整数的最短等差数列&#xff0c;既让包含这几个数&#xff0c;项数最少&#xff0c;若项数最少&#xff0c;肯定不能添加小于最小的和大于最大的&#xff0c;而且让项数最小&#xff0c;公差得大 等差数列的公差aj - ai / j - i; 这又是一个等差数…

批量给文件编排序号,支持数字序号及时间日期序号编排文件

当我们需要对文件进行编号的时候&#xff0c;我们可以通过这个工具来帮我们完成&#xff0c;它可以支持从 001 到 100 甚至更多的数字序号编号。也可以支持按照日期、时间等方式对文件进行编号操作。这是一种操作简单&#xff0c;处理起来也非常的高效文件编排序号的方法。 工作…

Dynamics365 ExportPdfTemplateExportWordTemplate两个Action调用的body构造

这两天在用ExportPdfTemplate做pdf导出功能时&#xff0c;遇到了如下问题InnerException : Microsoft.OData.ODataException: An unexpected StartArray node was found when reading from the JSON reader. A PrimitiveValue node was expected. 我的场景是使用power automate…