大侠帮忙看看,我的理解对吗?

牵着你的手 2014-11-06 12:42:14
看到这篇文章http://www.cnblogs.com/chenwenbiao/archive/2012/06/06/2537508.html
对SELECT ... FOR UPDATE 介绍,我看懂了如下:

举个例子: 假设商品表单products 内有一个存放商品数量的quantity ,在订单成立之前必须先确定quantity 商品数量是否足够(quantity>0) ,然后才把数量更新为1。

不安全的做法:

SELECT quantity FROM products WHERE id=3; UPDATE products SET quantity = 1 WHERE id=3;

为什么不安全呢?

少量的状况下或许不会有问题,但是大量的数据存取「铁定」会出问题。

如果我们需要在quantity>0 的情况下才能扣库存,假设程序在第一行SELECT 读到的quantity 是2 ,看起来数字没有错,但是当MySQL 正准备要UPDATE 的时候,可能已经有人把库存扣成0 了,但是程序却浑然不知,将错就错的UPDATE 下去了。

因此必须透过的事务机制来确保读取及提交的数据都是正确的。

于是我们在MySQL 就可以这样测试: (注1)

SET AUTOCOMMIT=0; BEGIN WORK; SELECT quantity FROM products WHERE id=3 FOR UPDATE; ===========================================

此时products 数据中id=3 的数据被锁住(注3),其它事务必须等待此次事务 提交后才能执行

SELECT * FROM products WHERE id=3 FOR UPDATE (注2) 如此可以确保quantity 在别的事务读到的数字是正确的。 ===========================================

UPDATE products SET quantity = '1' WHERE id=3 ; COMMIT WORK;

===========================================

提交(Commit)写入数据库,products 解锁。

注1: BEGIN/COMMIT 为事务的起始及结束点,可使用二个以上的MySQL Command 视窗来交互观察锁定的状况。

注2: 在事务进行当中,只有SELECT ... FOR UPDATE 或LOCK IN SHARE MODE 同一笔数据时会等待其它事务结束后才执行,一般SELECT ... 则不受此影响。

注3: 由于InnoDB 预设为Row-level Lock,数据列的锁定可参考这篇。

注4: InnoDB 表单尽量不要使用LOCK TABLES 指令,若情非得已要使用,请先看官方对于InnoDB 使用LOCK TABLES 的说明,以免造成系统经常发生死锁。

但有个疑问,既然quantity>0 的情况下才能update,那直接UPDATE products SET quantity = '1' WHERE id=3 where quantity >0
这样不就好了,后面跟个quantity >0就能保证了啊,何必要用select for update



还有这个介绍乐观锁的:
乐观锁机制在一定程度上解决了这个问题。乐观锁,大多是基于数据版本

( Version )记录机制实现。何谓数据版本?即为数据增加一个版本标识,在基于

数据库表的版本解决方案中,一般是通过为数据库表增加一个 “version” 字段来

实现。

读取出数据时,将此版本号一同读出,之后更新时,对此版本号加一。此时,将提

交数据的版本数据与数据库表对应记录的当前版本信息进行比对,如果提交的数据

版本号大于数据库表当前版本号,则予以更新,否则认为是过期数据。

对于上面修改用户帐户信息的例子而言,假设数据库中帐户信息表中有一个

version 字段,当前值为 1 ;而当前帐户余额字段( balance )为 $100 。

1 操作员 A 此时将其读出( version=1 ),并从其帐户余额中扣除 $50

( $100-$50 )。

2 在操作员 A 操作的过程中,操作员 B 也读入此用户信息( version=1 ),并

从其帐户余额中扣除 $20 ( $100-$20 )。

3 操作员 A 完成了修改工作,将数据版本号加一( version=2 ),连同帐户扣

除后余额( balance=$50 ),提交至数据库更新,此时由于提交数据版本大

于数据库记录当前版本,数据被更新,数据库记录 version 更新为 2 。

4 操作员 B 完成了操作,也将版本号加一( version=2 )试图向数据库提交数

据( balance=$80 ),但此时比对数据库记录版本时发现,操作员 B 提交的

数据版本号为 2 ,数据库记录当前版本也为 2 ,不满足 “ 提交版本必须大于记

录当前版本才能执行更新 “ 的乐观锁策略,因此,操作员 B 的提交被驳回。

这样,就避免了操作员 B 用基于 version=1 的旧数据修改的结果覆盖操作

员 A 的操作结果的可能。

从上面的例子可以看出,乐观锁机制避免了长事务中的数据库加锁开销(操作员 A

和操作员 B 操作过程中,都没有对数据库数据加锁),大大提升了大并发量下的系

统整体性能表现。

我不明白这个弄什么version有必要吗,直接update 表 set balance=balance-20 where id=1;
update 表 set balance=balance-80 where id=1;
这样两句话不就解决了,因为update 本来就会加锁,不可能出现同时减去的问题


求大侠指点,我理解的对吗?
...全文
215 3 打赏 收藏 转发到动态 举报
写回复
用AI写文章
3 条回复
切换为时间正序
请发表友善的回复…
发表回复
牵着你的手 2014-12-29
  • 打赏
  • 举报
回复
引用 2 楼 ACMAIN_CHM 的回复:
多谢大侠
ACMAIN_CHM 2014-12-28
  • 打赏
  • 举报
回复
牵着你的手 2014-12-28
  • 打赏
  • 举报
回复
来个人结贴,谢谢

56,677

社区成员

发帖
与我相关
我的任务
社区描述
MySQL相关内容讨论专区
社区管理员
  • MySQL
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧