丢失更新是数据中一个比较常见的经典问题,在做项目时我们有时可能会没有注意到这个问题,但这个问题相当重要,有时会带来比较严重的结果。下面我们就来讨论下这个丢失更新。
一、什么是丢失更新:
用一个操作过程来说明:
(1)会话Session1 中的一个事务获取(查询)一行数据,并显示给一个用户User1.
(2)会话Session2 中的另一个事务也获取这一行,但是将数据显示给另一个用户User2.
(3)User1 使用应用修改了这一行,让应用更新数据库并提交。会话Session1 的事务执行完毕。
(4)User2 也修改这一行,让应用更新数据库并提交。会话Session2 的事务执行完毕。
这个过程就叫做“丢失更新”,因为第(3)步做的操作会全部丢失(被第4步操作覆盖),最终数据库只会保存第(4)步的更新结果。这个情况在有些系统中可能不会有影响,但在有些系统中可能就影响很大了,举个简单的例子:
财务系统加工资,若公司本次调薪决定给员工张三加1k人民币,财务部两名操作人员A和B,过程情况若是这样的:
1)A操作员在应用系统的页面上查询出张三的薪水信息,然后选择薪水记录进行修改,打开修改页面但A突然有事离开了,页面放在那没有做任何的提交。
2)这时候B操作员同样在应用中查询出张三的薪水信息,然后选择薪水记录进行修改,录入增加薪水额1000,然后提交了。
3)这时候A操作员回来了,在自己之前打开的薪水修改页面上也录入了增加薪水额1000,然后提交了。
其实上面例子操作员A和B只要一前一后做提交,悲剧就出来了。后台修改薪水的sql:update 工资表 set salary = salary + 增加薪水额 where staff_id = ‘员工ID’。这个过程走下来后结果是:张三开心了这次涨了2k,操作员A和B都郁闷了。
二、解决思路:
基本两种思路,一种是悲观锁,另外一种是乐观锁; 简单的说就是一种假定这样的问题是高概率的,最好一开始就锁住,免得更新老是失败;另外一种假定这样的问题是小概率的,最后一步做更新的时候再锁住,免得锁住时间太长影响其他人做有关操作。
三、解决方案1(悲观锁)
a)传统的悲观锁法(不推荐):
以上面的例子来说明,在弹出修改工资的页面初始化时(这种情况下一般会去从数据库查询出来),在这个初始化查询中使用select ……for update nowait, 通过添加for update nowait语句,将这条记录锁住,避免其他用户更新,从而保证后续的更新是在正确的状态下更新的。然后在保持这个链接的状态下,在做更新提交。当然这个有个前提就是要保持链接,就是要对链接要占用较长时间,这个在现在web系统高并发高频率下显然是不现实的。
b)现在的悲观锁法(推荐优先使用):
在修改工资这个页面做提交时先查询下,当然这个查询必须也要加锁(select ……for update nowait),有人会说,在这里做个查询确认记录是否有改变不就行了吗,是的,是要做个确认,只是你不加for update就不能保证你在查询到更新提交这段时间里这条记录没有被其他会话更新过,所以这种方式也需要在查询时锁定记录,保证在这条记录没有变化的基础上再做更新,若有变化则提示告知用户。
四、解决方案2(乐观锁)
a)旧值条件(前镜像)法:
就是在sql更新时使用旧的状态值做条件,SQL大致如下 Update table set col1 = newcol1value, col2 = newcol2value…。 where col1 = oldcol1value and col2 = oldcol2value…。,在上面的例子中我们就可以把当前工资作为条件进行更新,如果这条记录已经被其他会话更新过,则本次更新了0行,这里我们应用系统一般会做个提示告知用户重新查询更新。这个取哪些旧值作为条件更新视具体系统实际情况而定。(这种方式有可能发生阻塞,如果应用其他地方使用悲观锁法长时间锁定了这条记录,则本次会话就需要等待,所以使用这种方式时最好统一使用乐观锁法。)
b)使用版本列法(推荐优先使用):
其实这种方式是一个特殊化的前镜像法,就是不需要使用多个旧值做条件,只需要在表上加一个版本列,这一列可以是NUMBER或 DATE/TIMESTAMP列,加这列的作用就是用来记录这条数据的版本(在表设计时一般我们都会给每个表增加一些NUMBER型和DATE型的冗余字段,以便扩展使用,这些冗余字段完全可以作为版本列用),在应用程序中我们每次操作对版本列做维护即可。在更新时我们把上次版本作为条件进行更新。
c)使用校验和法(不推荐)
d)使用ORA_ROWSCN法(不推荐)
五、结论:
综上所述,我们对丢失更新问题建议采取上面的悲观锁b方法或乐观锁b方法(蓝色字体已标注),其实这两种方式的本质都一样,都是在更新提交时做一次查询确认在更新提交,我个人觉得都是乐观的做法,区别在于悲观锁b方法是通过select……for update方式,这个可能会导致其他会话的阻塞,而乐观锁b方法需要多一个版本列的维护。
个人建议:在用户并发数比较少且冲突比较严重的应用系统中选择悲观锁b方法,其他情况首先乐观锁版本列法。
一、什么是丢失更新:
用一个操作过程来说明:
(1)会话Session1 中的一个事务获取(查询)一行数据,并显示给一个用户User1.
(2)会话Session2 中的另一个事务也获取这一行,但是将数据显示给另一个用户User2.
(3)User1 使用应用修改了这一行,让应用更新数据库并提交。会话Session1 的事务执行完毕。
(4)User2 也修改这一行,让应用更新数据库并提交。会话Session2 的事务执行完毕。
这个过程就叫做“丢失更新”,因为第(3)步做的操作会全部丢失(被第4步操作覆盖),最终数据库只会保存第(4)步的更新结果。这个情况在有些系统中可能不会有影响,但在有些系统中可能就影响很大了,举个简单的例子:
财务系统加工资,若公司本次调薪决定给员工张三加1k人民币,财务部两名操作人员A和B,过程情况若是这样的:
1)A操作员在应用系统的页面上查询出张三的薪水信息,然后选择薪水记录进行修改,打开修改页面但A突然有事离开了,页面放在那没有做任何的提交。
2)这时候B操作员同样在应用中查询出张三的薪水信息,然后选择薪水记录进行修改,录入增加薪水额1000,然后提交了。
3)这时候A操作员回来了,在自己之前打开的薪水修改页面上也录入了增加薪水额1000,然后提交了。
其实上面例子操作员A和B只要一前一后做提交,悲剧就出来了。后台修改薪水的sql:update 工资表 set salary = salary + 增加薪水额 where staff_id = ‘员工ID’。这个过程走下来后结果是:张三开心了这次涨了2k,操作员A和B都郁闷了。
二、解决思路:
基本两种思路,一种是悲观锁,另外一种是乐观锁; 简单的说就是一种假定这样的问题是高概率的,最好一开始就锁住,免得更新老是失败;另外一种假定这样的问题是小概率的,最后一步做更新的时候再锁住,免得锁住时间太长影响其他人做有关操作。
三、解决方案1(悲观锁)
a)传统的悲观锁法(不推荐):
以上面的例子来说明,在弹出修改工资的页面初始化时(这种情况下一般会去从数据库查询出来),在这个初始化查询中使用select ……for update nowait, 通过添加for update nowait语句,将这条记录锁住,避免其他用户更新,从而保证后续的更新是在正确的状态下更新的。然后在保持这个链接的状态下,在做更新提交。当然这个有个前提就是要保持链接,就是要对链接要占用较长时间,这个在现在web系统高并发高频率下显然是不现实的。
b)现在的悲观锁法(推荐优先使用):
在修改工资这个页面做提交时先查询下,当然这个查询必须也要加锁(select ……for update nowait),有人会说,在这里做个查询确认记录是否有改变不就行了吗,是的,是要做个确认,只是你不加for update就不能保证你在查询到更新提交这段时间里这条记录没有被其他会话更新过,所以这种方式也需要在查询时锁定记录,保证在这条记录没有变化的基础上再做更新,若有变化则提示告知用户。
四、解决方案2(乐观锁)
a)旧值条件(前镜像)法:
就是在sql更新时使用旧的状态值做条件,SQL大致如下 Update table set col1 = newcol1value, col2 = newcol2value…。 where col1 = oldcol1value and col2 = oldcol2value…。,在上面的例子中我们就可以把当前工资作为条件进行更新,如果这条记录已经被其他会话更新过,则本次更新了0行,这里我们应用系统一般会做个提示告知用户重新查询更新。这个取哪些旧值作为条件更新视具体系统实际情况而定。(这种方式有可能发生阻塞,如果应用其他地方使用悲观锁法长时间锁定了这条记录,则本次会话就需要等待,所以使用这种方式时最好统一使用乐观锁法。)
b)使用版本列法(推荐优先使用):
其实这种方式是一个特殊化的前镜像法,就是不需要使用多个旧值做条件,只需要在表上加一个版本列,这一列可以是NUMBER或 DATE/TIMESTAMP列,加这列的作用就是用来记录这条数据的版本(在表设计时一般我们都会给每个表增加一些NUMBER型和DATE型的冗余字段,以便扩展使用,这些冗余字段完全可以作为版本列用),在应用程序中我们每次操作对版本列做维护即可。在更新时我们把上次版本作为条件进行更新。
c)使用校验和法(不推荐)
d)使用ORA_ROWSCN法(不推荐)
五、结论:
综上所述,我们对丢失更新问题建议采取上面的悲观锁b方法或乐观锁b方法(蓝色字体已标注),其实这两种方式的本质都一样,都是在更新提交时做一次查询确认在更新提交,我个人觉得都是乐观的做法,区别在于悲观锁b方法是通过select……for update方式,这个可能会导致其他会话的阻塞,而乐观锁b方法需要多一个版本列的维护。
个人建议:在用户并发数比较少且冲突比较严重的应用系统中选择悲观锁b方法,其他情况首先乐观锁版本列法。
发表评论
-
Oracle函数介绍:decode
2011-12-10 14:49 738Sql代码 select sum( ... -
任重道远迁移路之DB2到Oracle
2011-11-25 10:56 801迁移之路任重而道远, ... -
GLOBAL_NAMES参数的详细研究
2011-11-23 12:59 872Oracle数据库GLOBAL_NAMES参数的相关知识是 ... -
Oracle作业job 没有自动调度起来
2011-11-22 11:52 1340Oracle作业job 没有自动调度起来 问题:有一同事报 ... -
Oracle与MySQL的几点区别
2011-11-21 11:46 722Oracle数据库与MySQL数据库的区别是本文我们主要要介绍 ... -
ORACLE 临时表空间使用率过高的原因及临时解决方案
2011-11-16 15:47 762数据库temp临时表空间增 ... -
Oracle 10g创建表空间步骤详解
2011-11-15 11:11 743Oracle 10g数据库中,当在数据库中创建用户时,基于应用 ... -
Oracle中的软解析和硬解析
2011-10-14 14:04 661问题一:哪个进程 ... -
F5 BIG-IP支持运行Oracle
2011-10-13 15:14 70410月13日,全球领先的应用交付网络厂商 F5 Netwo ... -
Oracle移动应用跨整个企业应用产品组合,发展势头迅猛
2011-10-12 14:39 1087甲骨文应用开发集 ... -
甲骨文推出oracle社交网络
2011-10-11 14:08 738在甲骨文全球大会 ... -
oracle数据库完整性约束规则
2011-10-10 15:28 621完整性约束用于增强数据的完整性,Oracle提供了5种完整 ... -
Oracle融合应用软件为企业在云计算中带来新的业务变革
2011-10-09 16:18 725Oracle融合应 ... -
Oracle 与戴尔携手:IT与业务融为一体
2011-10-08 14:55 6272011年10月4日,在Oracle Op ... -
应用Oracle组件实现动态Web数据库
2011-09-29 15:45 7731、用Oracle WebServer构建Web数据库应用 ... -
怎样做好数据库管家 怎么管理Oracle数据库
2011-09-28 15:01 685Oracle是一个最早商 ... -
http://www.oracleonline.net/home.php?mod=space&uid=7029&do=blog&quickforward=1&i
2011-09-27 11:56 2239凤凰网科技讯 北京时间9月27日消息,据彭博社报道,甲骨文联席 ... -
甲骨文教育基金会诚邀学生参加2012
2011-09-23 16:38 613· 2012年ThinkQuest竞赛由甲骨文教育基金会( ... -
Oracle在MySQL中新增商业扩展插件
2011-09-20 13:40 557racle目前宣布,支持为MySQL数据库新增商业扩展插件,但 ... -
Oracle认证:提高Oracle10G增量备份速度
2011-09-16 10:52 637问题:怎样才能提高Oracle 10G增量备份的速度? 解答 ...
相关推荐
在使用Oracle过各中经常会遇到密码丢失的时候,本文介绍了用两种方法来解决这个问题。
本解决方案主要关注Oracle数据库的应用管理,旨在提供一套全面、高效且稳定的管理策略,确保数据库系统的稳定运行,优化性能,以及保障数据的安全性。 首先,Oracle数据库的安装与配置是基础。在安装过程中,需要...
### Oracle常见问题的解决方法详解 #### 问题1:处理表中的坏块 在Oracle数据库中,如果遇到表中存在坏块的情况,这通常意味着数据的完整性受到威胁。坏块可能由硬件故障、电源问题或软件错误引起。解决这一问题的...
### Oracle商业智能银行解决方案 #### 一、概述 在当今高度竞争且日益规范化的金融行业中,银行和其他金融机构面临着巨大的挑战,这些挑战不仅来自于市场环境的变化和技术的快速发展,还包括客户期望的提升以及...
总之,解决Oracle数据库的乱码问题需要深入理解字符集的工作原理,确保所有环节从输入、存储到输出都保持字符集的一致性。在处理中文数据时,选择支持汉字的字符集如GBK或UTF-8尤为重要,以确保数据的准确显示和处理...
本篇文章将深入探讨Oracle错误及其解决方法,帮助你更好地理解和处理这些问题。 1. ORA错误类型与含义 ORA错误代码是Oracle数据库系统为了标识和解释特定错误而设定的。每个错误代码都包含了错误发生的特定上下文...
本文提供了一个完整的解决方案,旨在帮助用户在保持Linux中文环境的情况下,顺利安装Oracle并解决汉字乱码问题。 首先,我们需要安装Java Development Kit (JDK),因为Oracle数据库的安装和配置过程需要用到JDK。在...
总结起来,处理Oracle日志文件丢失的问题,关键步骤包括:以SYSDBA身份登录,关闭数据库,挂起启动,执行介质恢复,最后打开数据库并重置日志。此外,良好的数据库管理和备份策略是防止这类问题的关键。对于大型企业...
通过以上介绍可以看出,在Oracle数据库中,无论是通过备份数据还是闪回恢复方式,都可以有效地解决数据丢失问题。但在具体操作过程中,还需要结合实际情况,采取适当的预防措施,以确保数据的安全性和完整性。
以下是一份详细的步骤和解决方案,旨在帮助你克服这个挑战。 首先,我们需要理解Oracle数据库对字符集的支持。Oracle支持多种字符集,包括支持中文的ZHS16GBK、AL32UTF8等。ZHS16GBK是简体中文的GBK编码,而AL32UTF...
Oracle 数据库安装问题及其解决方法 Oracle 数据库是一种关系型数据库管理系统,广泛应用于金融、电信等行业。然而,在安装 Oracle 数据库时,会出现各种问题,影响数据库的正常使用。以下是Oracle 数据库安装问题...
这些问题可能涉及到性能、安全性、数据丢失或不一致等多方面,对于DBA(数据库管理员)来说,熟练掌握这些问题的解决方法至关重要。本篇将主要围绕Oracle数据库中常见的bug问题进行讨论,并提供相应的解决策略。 一...
以下是对这个问题的详细解析和解决方案: 首先,错误“ORA-01034: ORACLE not available”和“ORA-27101: shared memory realm does not exist”表明Oracle数据库实例无法启动,可能是由于共享内存区域未找到。这...
本文将详细介绍如何有效地向Oracle数据库插入Clob大段文本,以及在操作过程中可能遇到的问题与解决方案。 ### 一、理解CLOB类型 CLOB类型是Oracle数据库中用于存储大量文本数据的数据类型,它可以存储最大为4GB的...
Oracle数据库的任意距离零数据丢失保护方案主要集中在Data Guard (DG) 和Active Data Guard (ADG) 技术上,这两种技术都是Oracle数据库提供的一种全面的数据库复制解决方案,旨在确保业务连续性和数据安全性。...
本文将详细介绍如何解决SQL Server在大数据量插入时出现的速度慢以及数据丢失的问题,并提供具体的解决方案。 #### 插入速度慢的原因分析 1. **事务日志管理**:SQL Server默认情况下会对每一次插入操作进行事务...
理解错误代码含义并参照Oracle文档或在线社区的解决方案能帮助解决异常。 6. **空间管理**:表空间满是常见的问题。监控DBA_FREE_SPACE视图,及时清理不再使用的对象,或者增加数据文件来扩展表空间。理解如何创建...
本文将深入探讨Oracle删除表空间可能遇到的问题以及相应的解决方案,旨在帮助DBA们更好地管理和维护数据库。 首先,我们要明白表空间是Oracle数据库存储数据的逻辑结构,它由一个或多个数据文件组成。在删除表空间...
Oracle DataGuard 容灾解决方案 Oracle DataGuard 容灾解决方案是基于 Oracle 数据库的灾难恢复和高可用性解决方案,该方案通过建立异地的数据系统,实现远程数据容灾,确保业务的连续性。下面是该解决方案的详细...
* 自动间隔检测及其解决方案:如果主数据库与一个或更多个备用数据库之间的连接丢失(例如,由于网络问题),则在主数据库上生成的重做数据将无法发送到那些备用数据库上。一旦重新建立连接,Data Guard 就自动检测...