概述
对于我们做web的来说,都会遇到这样的情况:两个人(或多个人)同时打开同一条数据的修改页面,(如果不做处理)这时候就会发生很不好的现象:最后一个提交表单的人,会把之前所有提交的修改都覆盖掉了!
上面这个现象,我们常常说,这叫并发现象!其实,更专业一点的,这叫“数据的脏更新问题”。这个问题,在一般场景下,其实可以看成是无所谓的事情,但在一些比较严谨的或者“爱计较”的用户来说,这是不能忍的!因为我好不容易更新的东西,居然被别人覆盖了,甚至是一个领导修改完之后,发现居然被别人的修改覆盖了(我们就遇到过这样的现象,客户就向我们投诉了)!
对于上面的现象,我们不讨论要不要解决或有没有必要解决,我们要讨论的是,如果要解决,该怎么解决?我们系统中是解决了的,毕竟是收费客户投诉……
方案探讨
对于这个现象的解决方案来说,我先说几个方案,并讨论一下这几个方案的优缺点,大家可以多补充,一起探讨一下。
- 最简单最有效的,莫过于直接在各个修改的业务代码上加上判断。具体做法时,在进入修改页面时,把当前数据的修改时间(或有能记录数据变更的版本字段就更好)带到页面,在页面的form表单里hidden住,在提交修改时,对比这个时间,与服务器中当前数据的那个字段的值是否相等,如果相等,表示这段时间内没有被别人修改过,可以进行修改保存;否则就给出不能修改的提示。 这个方案的好处是:简单有效,灵活性很高,对不同的表可以取不同的合适的字段做对比信息;但其缺点也很明显:工作量大家、代码分散、维护困难等。
- 比较高端的做法是,在进入某数据的修改页面时,对当前数据加锁(锁的方式可以是数据库锁,也可以是在表中加一个标志字段表示数据正在被修改),这样别人在进入这条数据的修改页面时,系统会自动提示数据有别人在修改,在用户修改完之后将锁释放。 这个方式的优点是,防患于未改,而且因为使用锁机制,可以统一处理,减少工作量并易于后期维护;其缺点特别明显:就在于这个锁的释放!我们的web项目不像C/S结构,我们是无状态的一个交互方式,我们无法知道用户的操作状态,比如,我打开一个修改页面(这时加了锁),然后我直接把页面或浏览器关掉了,这时锁是不释放的,这样这条数据就永远被锁死了!这就得需要想一个特别的方案来释放这些“死锁”数据。
- 比较实际的做法,也是我使用的方法。就是根据自己的项目特征,从框架层面做一些处理。所以,本文将重点探讨一下这种方式的实现及不足之处。
框架层面统一解决脏更新的探讨
这个方案需要有三个基本条件:页面渲染使用统一接口(如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等切面技术实现,但思路是一致的。
欢迎大家参与探讨!
相关推荐
本文将深入探讨NFine框架的核心特性、设计原则以及在实际开发中的应用。 一、NFine框架概述 NFine框架作为一款开源项目,提供了丰富的基础组件,包括但不限于:权限管理、工作流引擎、数据字典、表单设计器、报表...
- **全栈框架**:提供从前端到后端全套解决方案的框架,如Django和Ruby on Rails等。 #### 三、技术框架的重要性和作用 1. **简化开发流程**:技术框架提供了一系列现成的解决方案,使得开发者无需从零开始编写...
这里我们主要探讨的是如何有效地管理和配置Java框架,以提高开发效率和应用性能。 首先,让我们来理解“整合JAVA框架配置文件”这个概念。在Java世界里,有许多成熟的框架如Spring、MyBatis、Struts等,它们都有...
本文探讨了J2EE设计模式与框架技术在构建Web系统中的应用,特别研究了Struts和Hibernate两大框架的作用。 在J2EE设计模式中,MVC(Model-View-Controller)模式是最核心的设计之一,它将应用程序分为三个核心组件:...
《基于Linux安全模块的通用框架研究与实现》这篇文章探讨了如何增强Linux操作系统的安全性,特别是引入强制访问控制(MAC)以对抗软件漏洞和恶意代码。文章指出,尽管过去几十年提出了许多增强访问控制模型,但目前...
本篇文章将探讨如何构建自己的MVC框架,我们将从核心概念、结构设计和实现细节三个方面展开。 一、核心概念 1. Model(模型):模型层负责处理应用程序的核心业务逻辑和数据管理。它与数据库或其他数据存储交互,...
本篇文章将深入探讨如何构建一个基于Redis的缓存框架,并与Spring Cache进行对比。 首先,让我们了解一下Redis。Redis(Remote Dictionary Server)是一款开源的、基于键值对的数据存储系统,支持字符串、哈希表、...
在研究方法上,本研究采用了数据分析和模型构建等手段,对智慧城市数据融合框架的设计和实现进行了深入探讨。通过实例分析,验证了所提出的数据融合框架的有效性和可行性。 总而言之,云计算在智慧城市数据融合中的...
通过以上分析,我们可以看出D2框架在装备管理领域的应用涵盖了前端开发的多个层面,从用户界面设计到数据处理,再到3D模型展示,全方位地支撑着装备管理系统的需求。对于开发者来说,理解和掌握D2框架能有效提升工作...
Spring、Struts 和 Hibernate 是...总的来说,SSH框架组合提供了企业级应用开发的强大工具集,涵盖了从用户界面到数据存储的各个层面。了解和掌握这些框架,对于Java开发者来说,是提升技能和适应复杂项目的关键步骤。
接下来,我们将基于这个信息,深入探讨与.NET框架设计相关的知识点。 ### .NET框架简介 .NET框架是由微软开发的一个软件框架,旨在为应用程序提供一个统一的运行环境。它支持多种编程语言,并且具有强大的类库支持...
本文旨在详细解析框架、组件、插件、控件以及中间件这几个概念,并探讨它们之间的区别与联系。 #### 几个概念 1. **类库** 类库是指程序员用来实现各种功能的一系列类的集合。例如`FileUtil`和`XMLUtil`等工具类...
Spring框架提供了众多模块,包括核心容器、数据访问/集成、Web、AOP、工具和消息等,覆盖了从基本的IoC容器到复杂的Web应用开发的各个层面。 二、核心容器 Spring的核心组件包括Bean工厂(Bean Factory)和...
本文将深入探讨一个名为“统一权限组件”的工具,它旨在提供一种高效、灵活且可扩展的权限管理解决方案。 统一权限组件,顾名思义,是为了实现系统中的用户权限统一管理而设计的模块。这样的组件通常包括用户管理、...
SSH框架提供了统一的异常处理机制,可以在全局异常处理器中捕获并处理这些异常,向用户展示友好的错误信息。 8. **测试**:确保登录注册功能正确无误,需要编写单元测试和集成测试。Spring提供MockMVC工具进行控制...
文章探讨了管理会计框架的问题,并从成本视角出发提出了新的理论框架构想。传统的管理会计框架常被认为理论体系不完善,无法充分解释和指导实际操作。作者指出,从成本信息的角度重建管理会计框架,有助于解决这一...
下面我们将逐一探讨这些技术及其在框架中的应用。 **SpringBoot** SpringBoot是Spring框架的简化版,旨在简化Spring应用程序的初始搭建以及开发过程。它预设了各种默认配置,如嵌入式Tomcat服务器、日志处理、自动...
本文主要探讨了这一领域的深入研究,特别关注了美国的网络安全框架(NIST Cybersecurity Framework,简称CSF)及其在关键信息基础设施中的应用。CSF旨在促进组织间的信息共享,提高网络安全风险管理能力,并为关键...
本文着重探讨了电子政务地理信息共享平台的框架设计,旨在解决信息孤岛、数据更新不及时以及不同尺度信息无法共享的问题。 1. **引言** 随着GIS(地理信息系统)、GPS(全球定位系统)和RS(遥感)技术的发展,...