一个经常被忽略的关于更新异常的问题

让我们一起来想象以下的一个场景:

我们正在开发一个B/S结构的CMS系统,数据库中有张表叫做"t_Article",用来保存文章信息。其中有三个字段:Article_ID、Article_Title、Article_Content,分别表示文章的ID、标题、正文,其中Article_ID为主键。OK,现在我们要为这个系统写文章修改功能,并且前台页面已经做好了,你会这么做?我想,你一定会首先根据GET过来的文章ID参数,获取相应文章的信息,也许你的SQL查询语句会是这样的:SELECT Article_Title,Article_Content FROM t_Article WHERE Article_ID='id'。下面,你会把获取到的标题和正文放入相应input和textarea标签的相应位置,以让它们显示在文本框中,供管理员修改。修改完后,你将会用Update语句更新数据库中的信息,例如:UPDATE t_Article SET Article_Title='title',Article_Content='content' WHERE Article_ID='id'。然后一切似乎很顺利,修改文章完全没有问题。接着,我们又投入别的功能的开发。

经过夜以继日的奋战,终于有一天系统交付使用了,我们开发小组得到了丰厚的酬金和两个星期的休假。

某一天,客户公司的网站管理员用这个CMS系统发布了一条信息,标题是"会议通知",正文为"本周三下午3点在公司主会议室开会"。可是,后来情况发生了改变,会议提前到两点进行,BOSS将这个信息告诉了管理员Alice,让他更新一下网站上的通知。于是Alice进入了后台管理,并进入了文章更新界面,就在这时,另一个管理员Bob也进入了文章更新页面,因为他觉得"本周三"这样的字眼不够明确,他想在后面添加上确切的日期会更好。大家请注意,关键问题来了!在这时,Alice还没有更新文章,所以,Bob读取的信息仍是原来的正文:本周三下午3点在公司主会议室开会。当Bob正在文本框里更改文章时,Alice已经完成了更新,她将正文改为"本周三下午两点在公司主会议室开会",并点击了更新按钮,于是数据库被更新了,可不幸的是,Bob这边文本框的信息可没有更新,还是先前读取的旧数据,当然,他也不知道Alice更新了数据库。于是,他乐呵呵的将正文改为"本周三(6月16日)下午3点在公司主会议室开会",然后同样点击了更新按钮。

我想大家已经猜出后来发生了什么,客户公司员工集体会议迟到,更遭的是,客户找到了我们的BOSS,于是我们开发小组被扣除了三个月的奖金。

为什么会发生如此悲惨的局面?我想大家已经很明白了,这种大家常用的更新数据开发方式,会导致数据更新异常问题。那么应该如何解决这个问题呢?也许你会说可以加锁,但是这相当麻烦,而且不易实现。下面,我提出一种简单的解决方案。

在上面的示例中,之所以会出现更新异常,关键是管理员在更新前,不能确定从他读取数据到点击更新按钮这段时间有没有人动过这些数据,如果在提交更新时,系统能判断出这段时间是否进行了更新,并且在有人更新过的情况下抛出一个异常而拒绝这次更新,并强制重新读取数据,问题就得到解决。这就是我的思路,而具体实现方法是,在每次读取信息后,将所有信息保存起来,在更新时,通过WHERE语句使每个字段都与原始数据进行匹配,如果数据被人动过,这条Update语句必然会失败。例如,我们可以将上文提到的Update语句改为下面的方式:(假设原始的标题和正文保存在oldTitle和oldContent中)UPDATE t_Article SET Article_Title='title',Article_Content='content' WHERE Article_ID='id' AND Article_title='oldTitle' AND Article_content='oldContent'。现在我们来想想,如果在这条语句执行前,数据已经被改动过,那么WHERE后面的语句指向的记录是不存在的,更新操作自然无法执行,这是一般会抛出一个异常。我们截获这个异常,然后做适当处理,例如提示更新不能进行,然后重新从数据库读出新的数据到页面文本框中。

到这里,问题已经得到解决了。当然,这个解决方案也会带来一定问题,例如Bob化了两个小时修改一篇文章,但不幸的是在他全神贯注修改文章时,这篇文章被Alice改动了,那么当倒霉的Bob点击更新按钮时,他将要接受刚才两个小时的汗水付之东流的残忍事实,但是,这总比全体会议迟到好吧……当然,我们可以更完美一些,例如通过Ajax技术将当前修改保存起来,以避免不幸发生。这已经超出本文讨论范围了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值