从框架层面统一解决脏更新的探讨

概述

         对于我们做web的来说,都会遇到这样的情况:两个人(或多个人)同时打开同一条数据的修改页面,(如果不做处理)这时候就会发生很不好的现象:最后一个提交表单的人,会把之前所有提交的修改都覆盖掉了!

        上面这个现象,我们常常说,这叫并发现象!其实,更专业一点的,这叫“数据的脏更新问题”。这个问题,在一般场景下,其实可以看成是无所谓的事情,但在一些比较严谨的或者“爱计较”的用户来说,这是不能忍的!因为我好不容易更新的东西,居然被别人覆盖了,甚至是一个领导修改完之后,发现居然被别人的修改覆盖了(我们就遇到过这样的现象,客户就向我们投诉了)!

         对于上面的现象,我们不讨论要不要解决或有没有必要解决,我们要讨论的是,如果要解决,该怎么解决?我们系统中是解决了的,毕竟是收费客户投诉……哭

方案探讨

         对于这个现象的解决方案来说,我先说几个方案,并讨论一下这几个方案的优缺点,大家可以多补充,一起探讨一下。

  1. 最简单最有效的,莫过于直接在各个修改的业务代码上加上判断。具体做法时,在进入修改页面时,把当前数据的修改时间(或有能记录数据变更的版本字段就更好)带到页面,在页面的form表单里hidden住,在提交修改时,对比这个时间,与服务器中当前数据的那个字段的值是否相等,如果相等,表示这段时间内没有被别人修改过,可以进行修改保存;否则就给出不能修改的提示。  这个方案的好处是:简单有效,灵活性很高,对不同的表可以取不同的合适的字段做对比信息;但其缺点也很明显:工作量大家、代码分散、维护困难等。
  2. 比较高端的做法是,在进入某数据的修改页面时,对当前数据加锁(锁的方式可以是数据库锁,也可以是在表中加一个标志字段表示数据正在被修改),这样别人在进入这条数据的修改页面时,系统会自动提示数据有别人在修改,在用户修改完之后将锁释放。  这个方式的优点是,防患于未改,而且因为使用锁机制,可以统一处理,减少工作量并易于后期维护;其缺点特别明显:就在于这个锁的释放!我们的web项目不像C/S结构,我们是无状态的一个交互方式,我们无法知道用户的操作状态,比如,我打开一个修改页面(这时加了锁),然后我直接把页面或浏览器关掉了,这时锁是不释放的,这样这条数据就永远被锁死了!这就得需要想一个特别的方案来释放这些“死锁”数据。
  3. 比较实际的做法,也是我使用的方法。就是根据自己的项目特征,从框架层面做一些处理。所以,本文将重点探讨一下这种方式的实现及不足之处。

框架层面统一解决脏更新的探讨

        这个方案需要有三个基本条件:页面渲染使用统一接口(如Velocity、FreeMark等渲染框架);数据库操作使用统一接口(如Hibernate、ibatis/myBatis等ORM框架,或自定义的统一操作入口);表中要有能做判断的字段。我们的项目使用的是Velocity+SpringMVC+Spring+iBatis(而我又对iBatis的常用操作接口做了封装,如:插入数据,根据id修改数据,根据指定的条件修改数据等等),而我们每个表中都正好有一个updateTime字段(更新时间),每次更新数据时,这个字段都会被更新为最新时间。

        有了这三个条件,我们就可以使用以下思路去做:在进入一个页面时,在对页面进行渲染前,我会把当前的页面中所用到的所有的实体类中的updateTime时间获取出来,并getTime()为long类型,做为判断的标志信息,hidden到页面的所有form表单中;在提交表单时,如果有这个hidden信息,则在根据id修改单条数据的接口中做判断。

        因为代码在公司研发网络(局域网),无法给出完整代码,这里我把关键地方的代码列出一下:

首先,要新建一个Filter,里面将这个hidden值取出来,放到线程池变量(ThreadLocal)中,这个就不需要写代码了吧?

其次,在渲染页面的地方,重写VelocityLayoutView.renderScreenContent方法,将其最后一行的改为:

velocityContext.put(this.sreenContentKey, appendVersionStamp(velocityContext, sw.toString()));

 appendVersionStamp这个方法代码核心如下:

 

 

private String appendVersionStamp(Context velocityContext, String pageHtml){
    if(StringUtils.isBlank(pageHtml) || (pageHtml.toLowerCase().indexOf("<form ")==-1 &&pageHtml.toLowerCase("<form>").indexOf()==-1)){
        return pageHtml;//如果页面内容为空,或没有form表单,则不处理
    }
//下面的代码比较多,就不写了,大概意思就是:将velocityContext中所有实体类找出来,然后取出其updateTime(如果updateTime为空,则取addTime),将实体类的类名+id+updateTime.getTime,作为一组标志。如果有标志,则把它hidden到每个from表单中,其hidden的name="_update_version_"。
}

再者,在根据id修改数据的接口中对其进行判断,其核心代码如下:

public <T> int updateById(T t){
    String version = VerifyHolder.getUpdateVersion();//从线程变量中取出Filter放置的页面提交上来的版本信息
    if(StringUtils.isNotEmpty(version)){//表单中有提交时,就可以更新。
        //这里的代码比较多,其逻辑为:根据id先从数据库中查出当前数据的updateTime(这里要缓存到线程变量中,因为如果业务中有多次修改操作的话,会引起误判),判断类名+id+updateTime.getTime(),前面类+id一致的情况下(这是确保验证的是同一条数据),如果updateTime不一致,则抛出异常,不给操作,否则就进行更新操作。
    }
}

 

优缺点探讨

优点:简洁明了,代码量小,维护方便,最重要的是,对开发透明。

缺点:对系统的要求较多;只能对根据id修改的接口才能做这样的统一处理,其它地方,因为是统一规则,无法个性化处理;

 

最后说一句:这种思路还可以使用AOP等切面技术实现,但思路是一致的。

 

欢迎大家参与探讨!

JavaScript 性能优化之框架 / 工程层面的优化 更快的冷启动和热更新(HMR)默认支持 Tree Shaking 和 Code Splitting自动按需引入模块在框架与工程层面优化 JavaScript 性能,是构建高质量前端应用的根本。通过合理选择框架配置构建工具开启 Tree Shaking按需加载资源等方式,不仅能显著提升加载速度,也能降低维护成本和复杂度。性能优化是一项系统工程,不应只停留在调代码阶段,而应贯穿在项目设计开发构建到上线的每一个环节中。 阅读详情

相关推荐

Android-Updater:自动化应用更新解决方案

本文还有配套的精品资源,点击获取 简介:为了提升用户体验和应用功能完整性,开发者需确保应用保持最新。 Android-Updater 提供一个封装了 DownloadManager 的高效用户友好更新流程。本文章将分析其工作原理、功能和实际应用。 DownloadManager 作为系统服务支持后台下载,而 Android-...

weixin_35756690的博客 2422

JPA操作数据库中的脏数据更新作用

脏数据来由 脏数据在临时更新(脏读)中产生。事务A更新了某个数据项X,但是由于某种原因,事务A出现了问题,于是要把A回滚。但是在回滚之前,另一个事务B读取了数据项X的值(A更新后),A回滚了事务,数据项恢复了原值。事务B读取的就是数据项X的就是一个“临时”的值,就是脏数据 脏数据更新 作用:持久化对象,一旦修改,事务提交的时候也会自动修改 1、没有执行meger,也能完成修改 2、加了meger,...

qq_43602395的博客 1415

C# 操作Excel的时候,出现"被呼叫方拒绝接受呼叫的异常"的解决方案(参考官方给出的解决方案)

首先官方有对这个错误给出解释和解决方案,连接如下: https://docs.microsoft.com/zh-cn/previous-versions/ms228772(v=vs.120)#%E5%8F%AF%E9%9D%A0%E7%BC%96%E7%A8%8B 简单来说,貌似是线程问题,我猜。。。 之前我尝试着在代码中添加 Thread.Sleep(1000); 来进行解决,这种办...

Ck_Max的博客 5769

脏读、丢失更新、不可重复读、幻读

脏读(Dirty Read): 事务T1更新了数据还未提交,这时事务T2来读取相同的数据,则T2读到的数据其实是错误的数据,即脏数据。基于脏数据所作的操作是不可能正确的。 脏页是内存的缓冲池中已经修改的page,未及时flush到硬盘,但已经写到redo log中。读取和修改缓冲池的page很正常,可以提高效率,flush即可同步。 脏数据是指事务对缓冲池中的行记录record进行了修改,但...

yishizuofei的博客 2146

从零到一:Ollama工具在RK3588上的深度优化实践

本文详细介绍了如何在RK3588开发板上深度优化Ollama工具,以高效运行DeepSeek模型。通过CPU与NPU负载平衡、模型量化、温度控制等策略,显著提升性能并降低功耗,适用于边缘计算场景。文章提供了具体的配置命令和优化方案,帮助开发者充分发挥RK3588的硬件潜力。

rgv23456789的博客 315

【同等学力】2005-数学⭐✨

有r个正方形排成一行,今用红、黄、白、蓝四种颜色给这个r个正方形染色,每个正方形只能染一种颜色,如果要求染红、黄、白色的正方形分别至少出现一个,问有多少种不同的染法?3、(4分)设G是一个有n个结点m条边的连通简单平面图,若n≥3,则m≤3n-6.4、(4分)证明:任何连通简单平面图至少有一个结点的度数不超过5

super_mochi1 306

总结oninput、onchange与onpropertychange事件的用法和区别

前端页面开发的很多情况下都需要实时监听文本框输入,比如腾讯微博编写140字的微博时输入框hu9i动态显示还可以输入的字数。过去一般都使用onchange/onkeyup/onkeypress/onkeydown实现,但是这存在着一些不好的用户体验。比如onchange事件只在键盘或者鼠标操作改变对象属性,且失去焦点时触发,脚本触发无效;而onkeydo...

weixin_34018169的博客 193

图神经网络实战(2)——图论基础

图论 (Graph theory) 是数学的一个基本分支,涉及对图研究。图是复杂数据结构的可视化表示,有助于理解不同实体之间的关系。图论提供了大量建模和分析现实问题的工具,如交通系统、社交网络和互联网等。在本节中,将介绍图论的基本原理,主要涉及三个方面:图属性、图概念和图算法。

盼小辉丶的博客 1万+

信息化孤岛探讨及解决思路(四)交付层面孤岛问题的解决

信息化孤岛探讨及解决思路(三)交付层面孤岛问题的解决问题讨论观点 问题 在(三)中,我们讨论了孤岛问题的解决,接下来深入一点进行分析讨论。 一般情况下一个单位会有有几类的终端在用,对不同用户来说,所有的信息系统中,他们关心的是什么? 延伸问题: 如果对用户来说,有几十套应用系统,怎么样才能保障所有的应用系统都能好用,怎么样才能够让这个东西落实到位? 讨论 针对这些问题,小伙伴们循例进行了如下,有些...

weixin_42801723的博客 564

云原生之容器编排实践-在K8S集群中使用Registry2搭建私有镜像仓库

基于前面搭建的3节点 Kubernetes 集群,今天我们使用 Registry2 搭建私有镜像仓库,这在镜像安全性以及离线环境下运维等方面具有重要意义。作为测试环境,本次使用 Registry2 搭建了私有镜像仓库,实际生产环境建议使用 Harbor;创建了一个 local-storage 的 StorageClass ,并使用本地磁盘的方式创建使用 PV ,实际建议使用 NFS 。

Heartsuit的博客 2462

【反封禁策略】集成 Undetected-Chromedriver:让 Browser-Use 绕过 Cloudflare 五秒盾

摘要:AI Agent如何突破Cloudflare检测的实战指南 本文针对AI Agent在Cloudflare检测下频繁受阻的问题,深入分析了undetected-chromedriver的工作原理与局限性。文章指出,Cloudflare 2026年的检测体系已升级为"浏览器指纹+IP信誉+协议指纹+行为模式"的多维交叉验证,单一伪装方案难以奏效。 核心内容包括: undetected-chromedriver的三层补丁体系解析 v2与v3版本的适用场景对比 两种Browser-Use集成方案:Selen

ZDQ58818的博客 284

分布式解决框架之Seata

Seata 是一款开源的分布式事务解决方案,致力于提供高性能和简单易用的分布式事务服务。Seata 将为用户提供了 AT、TCC、SAGA 和 XA 事务模式,为用户打造一站式的分布式解决方案。因为Seata主推的是AT(Automatic (Branch) Transaction)模式,同时也是最常用的,所以这里主要对AT模式做一下讲解

weixin_43410352的博客 3481

一文搞定 ST22 短转储 MEMORY_NO_MORE_PAGING:看懂 SAP Paging 机制,参数 rdisp/PG_SHM 与 rdisp/PG_MAXFS 怎么设才稳

SAP系统MEMORY_NO_MORE_PAGING错误通常源于Paging资源耗尽而非物理内存不足。关键排查点包括:通过ST22确认错误类型,ST02监控Paging使用情况,检查工作进程trace中的"no more free blocks"提示。解决方案建议将rdisp/PG_SHM和rdisp/PG_MAXFS设为相同值(如250000块≈2GB),使Paging完全在内存中运行。同时需优化易耗Paging的代码逻辑,如避免滥用EXTRACT命令和超大内存对象传输。典型案例如月末

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 335

4、支持动态模式演化的统一框架

本文提出了一种支持动态模式演化的统一框架,通过集成修改和版本控制机制,解决了数据库模式更新中的信息丢失、版本数量控制等问题。框架引入了类相关性级别的概念,结合对象版本的物理存储与计算,提高了数据库的灵活性和可维护性。此外,可扩展的语言允许用户根据需求动态指定模式更新语义,增强了系统的适应性。

juice的博客 573

医图论文 Arxiv‘24 | 自我先验引导的 Mamba-UNet 网络在医学图像超分辨率中的应用

作者提出了一种自我先验引导的 Mamba-UNet 网络(简称 SMamba-UNet)用于医学图像超分辨率。现有方法主要基于卷积神经网络(CNNs)或 Transformer。基于 CNN 的方法无法捕捉长距离依赖关系,而基于 Transformer 的方法由于其二阶计算复杂度,面临沉重的计算挑战。最近,状态空间模型(SSMs)尤其是 Mamba 出现了,它能够以线性计算复杂度建模长距离依赖。

小白学视觉 262

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

探讨ThinkPHP 6.0后台管理框架

通过熟悉和掌握其基本使用方法和开发规范、根据实际需求进行定制和扩展、以及关注框架的更新和升级等步骤,我们可以更好地发挥它的优势并构建出更加稳定、高效、安全的后台管理系统。简而言之,随着技术的不断发展和更新,ThinkPHP 6.0后台管理框架也会不断迭代和优化,为开发者提供更多的机会和挑战。这包括了解框架的架构设计和工作原理、熟悉常用的开发工具和插件、掌握代码编写和调试的技巧等。ThinkPHP 6.0后台管理框架提供了丰富的扩展和插件机制,我们可以根据项目的具体需求选择合适的扩展和插件进行集成和定制。

z123573z的博客 649

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

万字长文带你走进MySql优化(系统层面优化、软件层面优化、SQL层面优化)

缺点是可能会导致数据不一致,例如,当一个表的数据需要更新时,可能需要在多个小型数据库中进行更新操作。例如,可以将一个电商系统中的用户表、订单表、商品表等拆分成多个小型数据库,每个小型数据库中只包含一部分相关的表。垂直分库的优点是易于管理,每个小型数据库中包含的表都具有相似的特点。缺点是可能会导致数据不一致,例如,当一个表的数据需要更新时,可能需要在多个小型数据库中进行更新操作。如果表中存在自增主键,并且插入的数据量很大,那么每次插入数据时,MySQL 都需要重新计算自增主键的值,这可能会导致插入数据变慢。

龙飞的博客 3365

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

LobeChat能否持续学习?在线更新能力探讨

LobeChat本身不具备模型级持续学习能力,但通过RAG、插件系统和提示词工程,可实现知识更新与功能扩展。结合本地模型部署,能构建持续演进的AI助手生态,满足企业对智能体动态成长的需求。

weixin_34456923的博客 841

多智能体协作框架性能优化:代码层面与架构层面的双重提升

为了更好地展示多智能体协作框架性能优化的实践,我们将介绍一个名为"MultiAgentOpt"的开源项目。MultiAgentOpt是一个专注于多智能体协作框架性能优化的开源项目,提供了一套完整的性能监控、分析和优化工具。该项目旨在帮助开发者快速识别和解决多智能体系统中的性能瓶颈。

AI Agent Harness Engineering 227

Chameleon变色龙:滴滴开源的多端统一解决方案深度解析

Chameleon变色龙:滴滴开源的多端统一解决方案深度解析 【免费下载链接】chameleon ???? 一套代码运行多端,一端所见即多端所见 项目地址: https://gitcode.com/gh_mirrors/chamele/...

gitblog_01100的博客 684

Spring AI框架争论几时休

最近看到网上有一些人在鼓吹Spring AI框架多么多么好,应该接入,如果不接入就多low之类的,我不否定,但也不完全认同!诚然Spring AI有很大的优势,对接大模型简单,集成了各种向量库支持,方便使用者。但大家有没有发现,目前大模型发展太快了,新的框架层出不穷,指望Spring AI框架对接所有大模型是不是会成为瓶颈?有没有可能引出一些问题?

小程故事多的博客 874

从原理层面探究 React 是如何工作的

共计 10137 字,阅读时长约 25 分钟谁都没有看见过风,更不用说你和我了。但是当纸币在飘的时候,我们知道那是风在数钱。React 影响着我们工作的方方面面,我们每天都在使用它,只窥...

frontend_frank的博客 388

gRPC-Go认证中间件:统一认证与授权框架

在现代微服务架构中,安全认证和授权是构建可靠分布式系统的基石。gRPC-Go作为高性能RPC框架的Go语言实现,提供了一套完整的认证与授权中间件解决方案。本文将深入探讨gRPC-Go的认证授权框架,涵盖核心概念、实现原理、最佳实践以及高级用法。 ## 核心概念解析 ### 认证(Authentication)vs 授权(Authorization) 在深入技术细节前,我们先明确两个关键概念:...

gitblog_00955的博客 730

大模型训练新突破:统一框架让SFT与RL强强联合,性能飙升7个百分点

本文介绍清华大学等机构提出的统一策略梯度估计器(UPGE)框架,首次从理论层面统一了监督微调(SFT)与强化学习(RL)两种大模型后训练方法。基于此设计的混合后训练算法(HPT)能根据模型性能自适应切换学习策略,在数学推理任务上超越现有方法7个百分点。研究证明SFT与RL本质上是同一优化目标在不同条件下的体现,为LLM后训练提供了理论基础和实用方案。

aolan123的博客 962

mysql锁等待超时Lock wait timeout exceeded; try restarting transaction分析和代码层面以及数据库层面解决方案

mysql锁等待超时Lock wait timeout exceeded; try restarting transaction分析和代码层面以及数据库层面解决方案 1.首先看下案发现场 org.springframework.dao.CannotAcquireLockException: Error updating database. Cause: java.sql.SQLException...

u012799495的博客 1569

Android 网络 --framework层面 -two

Android 网络 --framework层面 -2NetworkAgentrematchNetworkAndRequests--非常核心的方法!! 在Android 网络 --framework层面-1 中大致描述了android 网络 fwk涉及到一些重要类,本章针对这些较为详细的介绍学习下 NetworkAgent NetworkAgent 是CS(ConnectivityService)和链路网络管理者(如WifiStateMachine、DataConnection)之间的信使,从CS的角度看N

阿奇的博客 1428
上一篇: HTML的空格与程序中的空格不同!
下一篇: 记录一下Velocity防Xss攻击
hellohank
博客等级 码龄19年 0粉丝 5原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值