PHP 板


LINE

看板 PHP  RSS
: : → 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 失败就代表库存不够,叫使用者重新回页面购买。 谢谢你的分享、我也顺便分享一下我的作法 我原本的问题是 「仓库」:1颗苹果 「甲」=>想买苹果 「乙」=>想买苹果 而买苹果的机制如为(1)先检查有没有苹果 (2)有的话就买 但要让整个机制都在Critical Secion底下、就需要一个lock 观念是 「Lock资源」=>篮子 机制是=>谁先抢到「篮子」、就能购买 if(篮子) { (1)检查有没有苹果 (2)有的话就买 } else //拿不到篮子的情况 { 等待拿篮子、并且尝试拿取 } 让我困扰的是、要制作这个Lock资源、必须要有一个具有实现lock功能的工具 於是我想到了MySQL的Primary Key 我的作法是、创造一个「MyLock」的Table 里面可以有很多资讯、但主要的就是要有一个LockName这个PrimaryKey (我这个Table其实也只放了这一个栏位) 所以作法如下: /*****Start*****/ //买东西之前 reslut = MySQL(insert into MyLock (LockName) value ("篮子")) while(result=>ErrorCode == 1062) //1062:重复的PK { //有人拿了篮子、等待一秒、之後尝试拿篮子 sleep(1); //先等待一个时间 result = MySQL(insert into MyLock (LockName) vlaue ("篮子"); } //Critical Secion [Start] (1)检查仓库有没有苹果 (2)有的话就买 //Critical Secion [End] MySQL(delete from MyLock where LockName = '篮子') //释放篮子资源 /*******End*******/ 这个方式挺容易的 而且没有复杂的MySQL判断跟指令 另外跟原本的lock 观念也一致 分享给大家@@、如果我的方法有什麽问题也欢迎讨论 --



※ 发信站: 批踢踢实业坊(ptt.cc)
◆ From: 175.180.127.239
1F:→ sunz5010:补充:有时候Critical Section要做的事情不只一样 03/25 10:58
2F:→ sunz5010:所以总不能都指望要做的事情只在资料库操作上 03/25 10:59
3F:→ sunz5010:用这样的方式、就能确保其他跟DB无关的操作也能够被保护 03/25 11:00
4F:→ sunz5010:Critical Section里面 03/25 11:00







like.gif 您可能会有兴趣的文章
icon.png[问题/行为] 猫晚上进房间会不会有憋尿问题
icon.pngRe: [闲聊] 选了错误的女孩成为魔法少女 XDDDDDDDDDD
icon.png[正妹] 瑞典 一张
icon.png[心得] EMS高领长版毛衣.墨小楼MC1002
icon.png[分享] 丹龙隔热纸GE55+33+22
icon.png[问题] 清洗洗衣机
icon.png[寻物] 窗台下的空间
icon.png[闲聊] 双极の女神1 木魔爵
icon.png[售车] 新竹 1997 march 1297cc 白色 四门
icon.png[讨论] 能从照片感受到摄影者心情吗
icon.png[狂贺] 贺贺贺贺 贺!岛村卯月!总选举NO.1
icon.png[难过] 羡慕白皮肤的女生
icon.png阅读文章
icon.png[黑特]
icon.png[问题] SBK S1安装於安全帽位置
icon.png[分享] 旧woo100绝版开箱!!
icon.pngRe: [无言] 关於小包卫生纸
icon.png[开箱] E5-2683V3 RX480Strix 快睿C1 简单测试
icon.png[心得] 苍の海贼龙 地狱 执行者16PT
icon.png[售车] 1999年Virage iO 1.8EXi
icon.png[心得] 挑战33 LV10 狮子座pt solo
icon.png[闲聊] 手把手教你不被桶之新手主购教学
icon.png[分享] Civic Type R 量产版官方照无预警流出
icon.png[售车] Golf 4 2.0 银色 自排
icon.png[出售] Graco提篮汽座(有底座)2000元诚可议
icon.png[问题] 请问补牙材质掉了还能再补吗?(台中半年内
icon.png[问题] 44th 单曲 生写竟然都给重复的啊啊!
icon.png[心得] 华南红卡/icash 核卡
icon.png[问题] 拔牙矫正这样正常吗
icon.png[赠送] 老莫高业 初业 102年版
icon.png[情报] 三大行动支付 本季掀战火
icon.png[宝宝] 博客来Amos水蜡笔5/1特价五折
icon.pngRe: [心得] 新鲜人一些面试分享
icon.png[心得] 苍の海贼龙 地狱 麒麟25PT
icon.pngRe: [闲聊] (君の名は。雷慎入) 君名二创漫画翻译
icon.pngRe: [闲聊] OGN中场影片:失踪人口局 (英文字幕)
icon.png[问题] 台湾大哥大4G讯号差
icon.png[出售] [全国]全新千寻侘草LED灯, 水草

请输入看板名称,例如:Gossiping站内搜寻

TOP