Hibernate多事务同时调用update(T t) ,字段被覆盖问题

前言

今天现网有个订单卡单了,经过排查发现没有任何异常日志,根据日志定位发现本应该更新的一个状态,也sql肯定执行了(使用了Hibernate的ORM框架),但是数据库里面的状态没有更新。大概逻辑如下

String hql= from orderInfo where id="PTTest";
OrderInfo orderInfo=commomDao.findSingle(hql);
orderInfo.setStatus("completed");
commonDao.update(orderInfo);

根据日志能确认,此段代码肯定是被执行了,但是数据库表的Status依旧是processing。

问题排查

这种情况,怀疑是在Status更新成completed之后,其他的事务把Status更新了成processing了。想佐证这种猜测,直接看数据库的bin log日志是最直观的。找大数据组同事找了日志时间点周围的bin log日志

确实在更新completed之后,又被其他事务更新成processing。后来从ELK中查看到对应requestLog日志,发现确实有请求更新了Status。

问题解决

直接用update 语句更新需要更新的字段

update orderInfo set Status="completed" where id="PTTest";

这种写法,更偏向Mybatis了,违背了Hibernate的思想了。如果我们不想写sql,还是希望以对象形式更新数据。我们也可以写一个方法

    public void update(Class<T> clazz, K id, Map<String, Object> columns) {if (CollectionUtils.isEmpty(columns.keySet())) {throw new ParameterException(RetCode.HIBERNATE_COLUMNS_ARGS_LENGTH_ERROR);}StringBuilder hqlBuilder = new StringBuilder(" update " + clazz.getSimpleName() + " set ");columns.keySet().forEach(k -> hqlBuilder.append(k).append(" = :").append(k).append(", "));hqlBuilder.append(" updateTime = :updateTime ");hqlBuilder.append(" where id = :id ");commonDao.execute((ExecuteCallback<Object>) session -> {Query query = session.createQuery(hqlBuilder.toString());columns.keySet().forEach(k -> query.setParameter(k, columns.get(k)));query.setParameter("updateTime", new Date());query.setParameter("id", id);return query.executeUpdate();});}

那么我们在调用的时候

Map<String, Object> params = new HashMap<>();
params.put("status", "completed");
update(OrderInfo.class, orderInfo.getId(), params);

其实update方法内部还是在拼凑sql。

使用@version注解

使用@Version注解是Hibernate提供的一种乐观锁机制,用于解决并发更新时的数据覆盖问题。乐观锁是一种锁策略,它假设多个事务在同一时间对同一条记录进行更新的可能性较低,因此不采用在更新前加锁的方式(即悲观锁),而是在更新时检查版本号,如果发现版本冲突,则认为有其他事务已经更新了该记录,此时可以选择重新获取最新数据并再次尝试更新,或者抛出异常告知用户。当使用@Version注解标注在实体类的某个属性上时,Hibernate会在每次读取该记录时自动将版本号加1,并在更新时检查当前版本号与数据库中的版本号是否一致。如果版本号不一致,说明有其他事务已经更新了该记录,此时Hibernate会抛出OptimisticLockException异常,从而避免了数据覆盖的问题。

使用@Version注解的步骤如下:

  1. 选择版本号字段:选择一个合适的字段作为版本号字段,通常是一个数值类型或时间戳类型的字段。
  2. 添加注解:在实体类中的版本号字段上添加@Version注解。
  3. 处理异常:在业务层捕获OptimisticLockException异常,根据实际需求进行处理,例如提示用户重新操作或重试更新。

通过使用@Version注解,可以在不使用显式锁的情况下,依靠版本号机制来控制并发更新,从而避免数据覆盖的问题。但需要注意的是,乐观锁并不能保证数据的绝对一致性,因为在检查版本号和实际更新之间仍然存在短暂的时间窗口,极端情况下仍然可能发生并发更新的问题。因此,在使用乐观锁时需要仔细评估并发风险,并结合实际业务需求进行选择。

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

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

相关文章

大模型训练:如何解决GPU万卡互联挑战?

如何解决GPU万卡互联的挑战 近日&#xff0c;字节跳动携手北京大学研究团队发布重磅论文&#xff0c;揭示了一项革命性技术&#xff1a;将大型语言模型训练扩展至超10,000块GPU的生产系统。此系统不仅解决了万卡集群训练大模型时的效率和稳定性难题&#xff0c;更标志着人工智能…

用dbms_shared_pool.purge清除执行计划

1.Oracle 11g如何清除share pool中某条SQL的执行计划 以前在Oracle 10g数据库上,如果遇到绑定窥探导致执行计划慢的情况,想要清除某条SQL的执行计划,让它硬解析,找了很久都没有找到直接操作share pool的方法&#xff08;总不能alter system flush shared_pool&#xff09;,只能…

rocketmq和rabbitmq总是分不清?

1. 官方解答 摘自百度搜索&#xff1a; 2. 通俗易懂的回答

【Gem5】获取构建教程

gem5-tutorial-hpca-2023 1 介绍 1.1 Gem5是什么1.2 Gem5可以用来做什么1.3 获取并构建gem5 gem5-tutorial-hpca-2023 打开网址&#xff1a; github 创建教程代码空空间 “Code” -> “Codespaces” -> “Create Codespace on master” GitHub Codespaces 是一个由…

LeetCode 157. Read N Characters Given Read4

个人专栏 🤺 leetcode 🧗 Leetcode Prime 🏇 Golang20天教程 🚴‍♂️ Java问题收集园地 🌴 成长感悟 欢迎大家观看,不执着于追求顶峰,只享受探索过程 LeetCode 157. 读取给定的 N 个字符 Read4 一、题目描述 Given a file and assume that you can only read th…

配置Kubectl命令自动补全功能

网站&#xff1a; bash-completion补全工具官网&#xff1a;https://caliban.org/bash/ 安装: 在日常管理k8s集群的时候&#xff0c;时刻都会使用到Kubectl命令行工具&#xff0c;但是该命令还是挺复杂的&#xff0c;使用中也记不住那么多的api选项&#xff0c;所以这里介绍…

python如何判断点是否在旋转矩形内部矢量

1. 简介 在计算机图形学和计算几何中&#xff0c;经常会遇到判断一个点是否在一个旋转矩形内部的问题。本项目方案旨在使用Python提供一种高效准确的算法来解决这个问题。 2. 算法原理 方法一&#xff1a; 为了判断一个点是否在一个旋转矩形内部&#xff0c;我们可以将问题…

最坏情况为线性时间的第k大元素

在统计和数据分析中&#xff0c;我们经常会遇到求最大值、最小值、中位数、四分位数、Top K等类似需求&#xff0c;其实它们都属于顺序统计量&#xff0c;本文将对顺序统计量的定义和求解算法进行介绍&#xff0c;重点介绍如何在最差时间复杂度也是线性的情况下求解第k大元素。…

在Debian 12系统上安装Docker

Docker 在 Debian 12 上的安装 安装验证测试更多信息引言 在现代的开发环境中,容器技术发挥着至关重要的作用。Docker 提供了快速、可靠和易于使用的容器化解决方案,使开发人员和 DevOps 专业人士能够以轻松的方式将应用程序从一个环境部署到另一个环境。 Docker 的安装过程在…

实用运维工具(转载)

1、查看进程占用带宽情况-Nethogs Nethogs 是一个终端下的网络流量监控工具可以直观的显示每个进程占用的带宽。 下载&#xff1a;http://sourceforge.net/projects/nethogs/files/nethogs/0.8/nethogs-0.8.0.tar.gz/download [rootlocalhost ~]#yum -y install libpcap-deve…

C语言—每日选择题—Day68

第一题 1、运行以下C语言代码&#xff0c;输出的结果是&#xff08;&#xff09; #include <stdio.h> int main() {char *str[3] {"stra", "strb", "strc"};char *p str[0];int i 0;while(i < 3){printf("%s ",p);i;} retur…

在win10上虚拟一个LoongOS系统(类似虚拟机)作为开发环境

文章目录 1.安装1.1.下载这三个东西1.2.安装好qemu。1.3.创建一个启动脚本startup_mate.bat&#xff0c;然后把三部分东西放到一起1.4.然后双击startup.bat就可以启动了。 2.文件的传输2.1.使能虚拟机系统的ssh2.2.连接ssh 3.Qt相关安装Qt安装opencv 1.安装 注意&#xff0c;一…

ClickHouse--17--argMin() 和argMax()函数

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 argMin() 和argMax()函数业务场景使用案例1.准备表和数据&#xff1a;业务场景一&#xff1a;查看salary 最高和最小的user业务场景二&#xff1a;根据更新时间获取…

再也不怕面试官问 OOM了,一次生产环境 Metaspace OOM 排查流程实操!

问题背景 小奎公司的运维同时今天反映核心业务一个服务目前 CPU 的使用率、堆内存、非堆内存的使用率有点高。刚反映没有过多久该服务就直接 OOM 了&#xff0c;以下是生产监控平台监控信息。 CPU 使用率监控 堆内存和非堆内存使用率 OOM 产生的日志报错信息 问题分析 根…

Go第三方框架--ants协程池框架

1. 背景介绍 1.1 goroutine ants是站在巨人的肩膀上开发出来的&#xff0c;这个巨人是goroutine&#xff0c;这是连小学生都知道的事儿&#xff0c;那么为什么不继续使用goroutine(以下简称go协程)呢。这是个思考题&#xff0c;希望讲完本文大家可以有个答案。 go协程只涉及用…

【STL】队列(queue)

队列 queue没有迭代器 Queue所有元素的进出都必须符合”先进先出”的条件&#xff0c;只有queue的顶端元素&#xff0c;才有机会被外界取用。Queue不提供遍历功能&#xff0c;也不提供迭代器。 头文件&#xff1a; #include <queue>queue<T> queT;//queue采用模…

Docker部署minio集群

1.基本定义 由于是非常轻量级的软件&#xff0c;所以架构上也没有这么复杂&#xff0c;他使用操作系统的文件系统作为存储介质&#xff0c;我们在向任意节点写数据的时候&#xff0c;minio会自动同步数据到另外的节点&#xff0c;而机制叫做erasure code&#xff08;纠删码&am…

Java基础知识总结(48)

&#xff08;1&#xff09;super关键字 1. super代表父类对象 2. 在构造器中访问父类的构造器&#xff08;创建子类对象时会先创建父类对象&#xff09; 3. super访问父类的实例变量 4. 访问父类的实例方法 如&#xff1a;/*** 父类* author Ray**/public class Animal {String…

linux内核驱动-在内核代码里添加设备结点

linux中&#xff0c;一切皆文件 我们在用户层用一些系统函数&#xff08;如&#xff1a;fopen等等&#xff09;时&#xff0c;会进入内核&#xff0c;内核会在字符注册了的设备号链表中查找。如果找到就运行我们写的设备文件的&#xff08;驱动&#xff09;函数 我们在前面已经…

【滑动窗口】无重复字符的最长字串

给定一个字符串 s &#xff0c;请你找出其中不含有重复字符的 最长子串的长度 示例 1: 输入: s "abcabcbb"输出: 3 解释: 因为无重复字符的最长子串是 "abc"&#xff0c;所以其长度为 3。 示例 2: 输入: s "bbbbb"输出: 1解释: 因为无重复字…