小心:防止数据库数据写覆盖
来源:互联网 发布:u3d java工资大概多少 编辑:程序博客网 时间:2024/05/01 02:04
常常在项目中见到这样的DML语句:
这么简单的语句,有什么稀奇的地方呢?我来模拟一个场景,用户A在页面上查询到这条ID=12345的记录,他看到column1的值是1,他想更新到2 。于是他点击了更新,同时用户B也看到了这条记录,他看到这条记录的column1的值也是1,他想更新到3,于是他也点击更新。这个时候问题来了,由于用户A心里想的是2,这个时候他更新完毕之后,查询出来看到的值却是3.这时估计用户A感觉灵异事件发生了...
上面是一个很简单的场景,而且在项目中也经常遇到,这就是数据写覆盖问题。刚出来工作的同学最容易犯这个问题,我这里提供几个方法权当供大家参考:
①利用语句级SQL执行的原子性
假设一个总额字段 total初始值是20,如果以后每次总额增加10元,我们就要更改这个字段。
容易犯的错误:
首先,
然后在程序中 最后一步 解决方案:
这里直接利用语句级的原子性,不用先查询再做加法。
②悲观锁:利用for update行锁(先查询再更新)
同样是上面的例子。
解决方案:
首先,开启事务
然后在程序中 之后更新
最后,关闭事务。
注意,这里几条基于一定要在事务中执行。
③乐观锁:更新时检查版本标志
新增一个字段version,每次update都要对这个version加1,更新的时候检查这个version是否变化,如果已经变化了,表示被更新过了。
首先
假设这里version=20,
然后在程序中 之后更新
检查更新语句的返回值是否等于1,如果不等于1表示更新不成功,根据实际业务情况,可以直接反馈给用户,或者再做其他重试处理。
上面三种方法一般都有自己的使用场合:
①第一种方法,一般适合某个字段需要根据更新前的状态动态增加或者减少等做出变化的情况,这类需求处理起来无往不利。
② 第二种方法适用于用户更新一定要保证成功的情况,即更改及有效的情况,如果并发更新程序很高,一般采用这种方式比较妥当,可以减少更新失败的情况。
③第三种方法,不需要对数据进行事先锁定,更新只需要检查版本标志,即可知道是否已经被别人更新过了,适合于对更新成功要求不高的用户,即可以通过简单提示,然后让用户重新查询再修改的情况。如果并发程度很高,这种方法失败的几率也很高,所以一般不太适合。
当然,这些都要根据实际情况来决定,一般系统中会综合运用上诉的几种方法来解决问题。总之一句话,写覆盖的问题大家一定要引起重视,不然出现了问题,你也只能按灵异事件处理了,因为并发问题,有的数据怎么来的都不知道。
- UPDATE table1 set column1=2 where id=12345
上面是一个很简单的场景,而且在项目中也经常遇到,这就是数据写覆盖问题。刚出来工作的同学最容易犯这个问题,我这里提供几个方法权当供大家参考:
①利用语句级SQL执行的原子性
假设一个总额字段 total初始值是20,如果以后每次总额增加10元,我们就要更改这个字段。
容易犯的错误:
首先,
- select total from table1 where id=12345
- var temp=total+10
- UPDATE table1 set total=#temp# where id=12345
- UPDATE table1 set total=total+10 where id=12345
②悲观锁:利用for update行锁(先查询再更新)
同样是上面的例子。
解决方案:
首先,开启事务
- select total from table1 where id=12345 for update
- var temp=total+10
- UPDATE table1 set total=#temp# where id=12345
注意,这里几条基于一定要在事务中执行。
③乐观锁:更新时检查版本标志
新增一个字段version,每次update都要对这个version加1,更新的时候检查这个version是否变化,如果已经变化了,表示被更新过了。
首先
- select total,version,id from table1 where id=12345
然后在程序中
- var temp=total+10
- UPDATE table1 set total=#temp#,version=version+1 where id=12345 and version=20
上面三种方法一般都有自己的使用场合:
①第一种方法,一般适合某个字段需要根据更新前的状态动态增加或者减少等做出变化的情况,这类需求处理起来无往不利。
② 第二种方法适用于用户更新一定要保证成功的情况,即更改及有效的情况,如果并发更新程序很高,一般采用这种方式比较妥当,可以减少更新失败的情况。
③第三种方法,不需要对数据进行事先锁定,更新只需要检查版本标志,即可知道是否已经被别人更新过了,适合于对更新成功要求不高的用户,即可以通过简单提示,然后让用户重新查询再修改的情况。如果并发程度很高,这种方法失败的几率也很高,所以一般不太适合。
当然,这些都要根据实际情况来决定,一般系统中会综合运用上诉的几种方法来解决问题。总之一句话,写覆盖的问题大家一定要引起重视,不然出现了问题,你也只能按灵异事件处理了,因为并发问题,有的数据怎么来的都不知道。
早先我也曾提到过这里的问题:《保持业务数据同步》
转载:http://blog.csdn.net/lovingprince/article/details/3519843
0 0
- 小心:防止数据库数据写覆盖
- 小心:防止数据库数据写覆盖
- 防止覆盖集合中的数据
- oracle 防止select后update覆盖数据
- ios 小心方法重复覆盖
- Mysql的Bin log数据恢复:不小心删除数据库
- 数据库不小心数据发生改变的恢复方法
- SQL2000数据库同名覆盖数据恢复
- 为什么防止跨数据库操作数据?
- 项目/数据库中的写覆盖问题与解决
- 写数据到数据库SQLserver
- 数据库小心得
- 小心数据集乱套
- 小心,异步数据
- github不小心同步覆盖了本地文件
- 写代码一定要小心、谨慎
- ERP软件数据库覆盖数据恢复成功/重装数据库系统软件,导致同名文件覆盖
- 如何通过for循环添加对象到集合(防止数据覆盖)
- 高跟鞋
- UINavigationController和UITabBarController的属性之间的一些继承关系
- safe_mode 开启后linux下影响
- 二位小数
- 称砝码
- 小心:防止数据库数据写覆盖
- asp.net登录页面验证(js方法)【转载】
- 欢迎使用CSDN-markdown编辑器
- 在Linux下如何用Python监控键盘记录
- Android 使用存放在存assets文件夹下的SQLite数据库
- C/C++ 快速排序算法
- 11-系统环境变量小常识
- 解决浏览器缓存问题
- Android 之 Android Studio