关于分布式锁的释放和spring事务提交时机不符合预期从而带来的数据不一致的问题

提要

首先注意,本文探讨的不是分布式事务,请读者注意区分!
在我们的日常开发种,分布式锁和spring事务是常见的两种控制数据一致性的方式。
分布式锁和spring事务各自的作用就不做阐述了,不是本文重点,本文重点阐述一下锁释放和事务提交的问题。

不一致的场景

下面这个场景是抽象出来的一个很简单的场景
我们业务种经常会遇到,比如线程A线程B同时调用test0
假如A先获取到锁,在test1中更新了x字段
在B获取到锁的时候,拿到的x的值是符合预期的么?

@SneakyThrows
@Override
public void test0() {CommonServiceImpl self = (CommonServiceImpl) AopContext.currentProxy();log.info("test0----------------------");self.test1();self.test2();
}@SneakyThrows
@Override
public void test1() {try {// 这里就是普通的一个加锁和释放锁的方法,在两个方法内分别打印个加锁和释放锁的日志LockUtil.acquireLock("test1");log.info("test1----------------------更新数据库里的某个字段x");Thread.sleep(5000);} finally {LockUtil.releaseLock("test1");}
}@SneakyThrows
@Override
public void test2() {log.info("test2----------------------做一些其他无关紧要的查询");Thread.sleep(5000);
}

显然是不符合预期的,B线程拿到的x大概率是A更新前的,如果这里是一些库存之类的场景,很可能就出现超卖的现象。
至于为什么,我们可以看下运行的打印结果
在这里插入图片描述
原因就在于锁的释放是在事务提交之前(当然这里的前提是这三个方法在一个事务中),B在拿到锁去查询x的值的时候,A虽然已经更新完了x的值并且释放了锁,但是事务还没来得及提交,所以B拿到的仍然是旧的值,此时去更新就会出问题。
那么什么情况下不会出问题呢?

  1. B线程获取到锁,去查询x的值的时候,A线程中test2的方法刚好执行完提交了事务,这个时候查询的值就是修改后正确的值(显然我们开发不能碰运气)
  2. 这几个方法都没有事务,B只要获取到锁,那么拿到的就是最新的数据(这种场景是存在的,而且我们开发中也提倡没必要用事务的场景就不需要用,需要的场景尽可能用小事务,当然这是开发之前就考虑的问题了)
  3. 某些数据库的事务隔离机制可能不存在这种场景(略有耳闻,但我确实没见过)
  4. 锁加在事务之外的时候,这样也可以保证锁的释放在事务提交之后(但是有时候避免不了事务传播和嵌套)
  5. 还有些场景,比如上面的代码中,哪怕test0只调用了test1(),也有可能出现上述场景,因为上面的锁本质上还是加在事务里面的,虽然它锁的内容包含了整个方法,但是遇到一些极端情况,比如数据库性能不太好的时候,就会出现线程B拿到锁的时候A的事务还没提交。
    所以,我们还是需要考虑,如果真存在这种场景,我们该怎么处理?

通过事务同步管理器手动控制

大家可以看下代码有什么区别

@SneakyThrows
@Override
public void test0() {CommonServiceImpl self = (CommonServiceImpl) AopContext.currentProxy();log.info("test0----------------------");self.test1();self.test2();
}@SneakyThrows
@Override
public void test1() {try {LockUtil.acquireLock("test1");log.info("test1----------------------更新数据库里的某个字段x");Thread.sleep(5000);} finally {LockUtil.unlockAfterTransaction("test1");}
}@SneakyThrows
@Override
public void test2() {log.info("test2----------------------做一些其他无关紧要的查询");Thread.sleep(5000);
}

先来上运行结果
在这里插入图片描述
很显然,这里的释放锁过程跑到了test2执行完成之后,也就是事务提交之后。
这样就保证了B拿到锁的时候,A的事务是已提交状态
这里主要就是把
LockUtil.releaseLock(“test1”)
换成了
LockUtil.unlockAfterTransaction(“test1”)

public static void unlockAfterTransaction(String lockName) {//事物完成后释放锁TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {@Overridepublic void afterCompletion(int status) {super.afterCompletion(status);releaseLock(lockName);}});}

就是把之前释放锁的方法包一层,通过事务同步管理器加个判断

事务同步管理器的其他用处

除了确保锁释放和事务提交的时机之外,事务同步管理器还可以有其他作用,比如你在一个方法中调用异步方法,当前事务提交成功之后调用和立刻调用就,结果可能完全不同,下面是一个简单的示例:

立刻调用

public void fireAsynchronous(final String type, final Object... parameters) {this.asyncEventListenerExecutor.execute(new Runnable() {public void run() {EventManager.this.fire(type, parameters);}});}

事务成功提交之后再调用

public void fireSyncOnTransactionSuccess(final String type, final Object... parameters) {TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {public void afterCommit() {EventManager.this.fire(type, parameters);}});}

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

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

相关文章

AIGC技术的发展现状与未来趋势

AIGC(人工智能生成内容)技术是近年来快速发展的领域之一,它涉及使用人工智能来创建或编辑内容,包括文本、图像、音乐和视频等。这项技术的进步为各个行业带来了革命性的变化,同时也引发了一系列伦理和风险问题。 一、技…

宜搜科技死磕港交所上市:从搜索引擎到广告投放,业绩疲态凸显

近日,宜搜科技控股有限公司(下称“宜搜科技”)向港交所递交招股书,计划在香港主板上市,中银国际为其独家保荐人。 值得注意的是,宜搜科技已在资本市场辗转多年。该公司曾于2014年向纽交所递交上市申请&…

CentOS7编译jsoncpp静态库

1. 官网下载源码 github地址:GitHub - open-source-parsers/jsoncpp at update 2. 编译 Unzip jsoncpp-master.zip Cd jsoncpp-master mkdir -p ./build/debug cd ./build/debug/ cmake -DCMAKE_BUILD_TYPEdebug -DBUILD_SHARED_LIBSOFF -DCMAKE_ARCHIVE_OUTPUT_D…

docker快速搭建部署mqtt

文章目录 前言一、mqtt是什么?二、使用步骤1.引入库2.创建临时容器3.创建挂在目录4.将临时容器的配置挂载到宿主机中5.删除临时容器6.运行容器并挂载文件7.登录EMQX内置的管理控制台 总结 前言 一、mqtt是什么? MQTT(Message Queuing Teleme…

Ts类型体操详讲 之 extends infer (下)

目录 1、函数 (1)提取参数类型 (2)提取返回值类型 2、构造器 (1)提取构造器返回值 (2)提取构造器参数类型 3、索引类型 本章我们继续上节的内容继续,展示我们对ex…

提升你的C编程技能:使用cURL下载Kwai视频

概述 本文将介绍如何利用C语言以及cURL库来实现Kwai视频的下载。cURL作为一个功能强大的网络传输工具,能够在C语言环境下轻松地实现数据的传输。我们还将探讨如何运用代理IP技术,提升爬虫的匿名性和效率,以适应Kwai视频平台的发展趋势。 正…

报告!这里发现了一个赛博炼丹的神级平台!

众所周知,“赛博炼丹”是一个AI开发研究领域古老又神秘的活动,它往往对炼丹平台有很高的要求。如果你也是一路从“炼丹小白”成长到“资深AI算法工程师”,那你一定懂我在说什么?说好了,天台见! GpuMall智算…

力扣HOT100 - 108. 将有序数组转换为二叉搜索树

解题思路: 二叉搜索树一般使用中序遍历 class Solution {public TreeNode sortedArrayToBST(int[] nums) {return helper(nums,0,nums.length-1);}public TreeNode helper(int[] nums,int left,int right){if(left>right) return null;//确定根节点//总是选择中…

【缓存服务】⭐️自定义实现一个简易的数据缓存

目录 🍸前言 🍻手写缓存服务 (1)缓存实体类 (2)缓存工具类 (3)测试缓存服务 🍷已有的缓存工具 🍹章末 🍸前言 俗话说 有轮子不用 就是玩 开个…

条件生成对抗网络(cGAN)在AI去衣技术中的应用探索

随着深度学习技术的飞速发展,生成对抗网络(GAN)作为其中的一个重要分支,在图像生成、图像修复等领域展现出了强大的能力。其中,条件生成对抗网络(cGAN)通过引入条件变量来控制生成模型的输出&am…

Spring SpringBoot(详解)

1. Spring简介 1.1 Spring 核心设计思想 1.1.1 Spring 是什么? Spring 是包含了众多⼯具⽅法的 IoC 容器。Spring 指的是 Spring Framework(Spring 框架),它是⼀个开源框架,Spring ⽀持⼴泛的应⽤场景,它…

手撕AVL树(map和set底层结构)(1)

troop主页 今日鸡汤:Action may out always bring happiness;but there is no happiness without action. 行动不一定能带来快乐,但不行动一定不行 C之路还很长 手撕AVL树 一 AVL树概念二 模拟实现AVL树2.1 AVL节点的定义 三 插入更新平衡因子&#xff0…

SpringBoot学习之Kafka下载安装和启动【Mac版本】(三十三)

一、配置Java环境变量 在启动Kafka之前,你需要先正确配置好你的Java环境变量。可以在终端输入java -version检查java环境变量是否配置正确,在Mac上如何配置java环境变量,请读者自行网上搜索操作之,此处不赘叙。 二、下载安装Kafka 1、下载Kafka:Apache Kafka,这两个版本…

四川赢涟电子商务有限公司深耕抖音电商服务

在当今数字化、网络化高速发展的时代,电子商务行业异军突起,成为推动经济增长的重要力量。四川赢涟电子商务有限公司凭借其敏锐的市场洞察力和创新精神,专注于抖音电商服务,致力于为广大消费者提供便捷、高效、个性化的购物体验&a…

Paddle 1.8 与 Paddle 2.0 API 映射表

安装2.6的paddlepaddle之后总是报fluid的错误,查询得知这个接口已经弃用了,但是一直找不到替换接口,偶然查询报错信息的时候找到了映射表,转存一下。 Paddle 1.8 与 Paddle 2.0 API 映射表

如何优雅地Spring事务编程

本文已收录至Github,推荐阅读 👉 Java随想录 微信公众号:Java随想录 在开发中,有时候我们需要对 Spring 事务的生命周期进行监控,比如在事务提交、回滚或挂起时触发特定的逻辑处理。那么如何实现这种定制化操作呢&am…

直播报名 | 科技出海新势力,遥感+AI助力一带一路

遥感技术的出海之路顺畅吗? 国内外遥感应用的关注点相同吗? 目前珈和主要辐射哪些海外国家? … 上周数据赋农季第三期《科技出海,遥感AI赋能“一带一路”提升种植园规模效益》直播预告一出,小伙伴们纷纷来咨询珈和的海…

CentOS安装htop工具

启用 EPEL Repository 安装Htop 首先启用 EPEL Repository: yum -y install epel-release启用 EPEL Repository 后, 可以用 yum 直接安裝 Htop: 安装htop yum -y install htop安装成功 输入htop使用工具 htop安装glances工具 yum install glances

Springboot+Vue项目-基于Java+MySQL的企业客户管理系统(附源码+演示视频+LW)

大家好!我是程序猿老A,感谢您阅读本文,欢迎一键三连哦。 💞当前专栏:Java毕业设计 精彩专栏推荐👇🏻👇🏻👇🏻 🎀 Python毕业设计 &…

前端零代码开发实践:页面嵌套+逻辑连线0开发扩展组件,实现切换开关控制扇叶转动。能无代码封装扩展组件,有别于常规的web组态或低代码平台

前言: 官网:http://www.uiotos.net/ 什么是 UIOTOS? 这是一款拥有独创专利技术的前端零代码工具,专注于解决前端界面开发定制难题,原型即应用!具有页面嵌套、属性继承、节点连线等全新特性,学习门槛低…