作者roga (任性)
看板PHP
标题Re: [请益] 同时写入资料库的问题
时间Fri Mar 25 00:51:21 2011
: → mesak:你可以试试 LATIV 的购物网站,我曾经下订单之前 有货
: → mesak:正准备按下去的时候 就没货了= =
: → mesak:AJAX 跑回圈取得 目前的量,谁先按下购买就处理谁的
: → knives:应该是有人点的时候,就改变货品数量,在update的时候要锁
: → knives:资料库,update完就commit解锁了
: 推 roga:楼上,用哪种方法"锁"资料库, 愿闻其详 ?
: → cokellen:楼上,MySql ,innodb, transaction
: → sunz5010:我用一个新的table的PK、然後用insert去做
: → sunz5010:要写入资料库之前、先inset这个PK、可以insert就写入
: → sunz5010:不能insert就等待别人delete之後再做写入资料库
: → sunz5010:因为用mysql insert一个pk不会有重复的问题
: → sunz5010:如果有人先抢先写入、後来的人会出现1064的error code
: → sunz5010:等第一个人delete之後、第二个人就能正常inset
: → sunz5010:利用这个功能就可以达到[LOCK]的效果、还不错用@@
假设您有个栏位纪录数字,叫做 qty 然後有个 pkey 叫做 id 。
提供一个作法给您参考:
/**
CREATE TABLE `scart` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`title` varchar(10) NOT NULL,
`qty` int(11) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8
*/
$id = 1;
$qty = 2;
$dbh = new PDO('mysql:host=localhost;dbname=benchmark','test','password',
array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8"));
$dbh->beginTransaction();
$sth = $dbh->prepare("SELECT qty FROM scart WHERE id = :id FOR UPDATE");
用 select for update 在 commit (rollback) 前都会有 exclusive lock (row level)
$sth->execute(array(':id'=> $id));
$result = $sth->fetch();
if(($result['qty'] - $qty) >= 0)
{
$sth = $dbh->prepare("UPDATE scart SET qty = qty - :qty WHERE id = :id");
$sth->execute(array(':qty' => $qty, ':id' => $id));
$dbh->commit();
}
else
{
echo "not enough stock." . PHP_EOL;
$dbh->rollback();
}
以上是先拿出库存再来算数量,但是您要考虑 innodb_lock_wait_timeout ,
这个预设是 50 秒,等起来有点久。或是考虑另一种作法,不要 select 直接计算
$sth = $dbh->prepare("UPDATE scart SET qty = qty - :qty
WHERE id = :id and qty - :qty > 0");
$sth->execute(array(':qty'=>$qty, ':id'=>$id));
然後 update 失败就代表库存不够,叫使用者重新回页面购买。
--
The Internet: where men are men, women are men, and children are FBI agents.
--
※ 发信站: 批踢踢实业坊(ptt.cc)
◆ From: 202.174.4.5
※ 编辑: roga 来自: 202.89.121.16 (03/25 12:24)