作者gpmm (银色)
看板PHP
标题Re: [请益] 请问关於不重复编号
时间Wed Sep 5 03:21:45 2012
※ 引述《koizumisyou (不小的挑战)》之铭言:
: 我的需求为用户端送出一个表单时
: 编号为 920904001,若重复,则取该栏位最大值+1
: 9为固定号码,2为西元年最後一码,0904为日期,001是流水编
: 为了不重复,参考网路作法
: 1、变数C预设值是当天的001
: 2、假设经比对 变数 total不等於0,也就是里头已经有该编号
: 3、那麽就取最大值+1
: 我的问题是
: 问题1:为什麽多人使用时还是会重复编号??
: 问题1-1:重复的编号我观察结果发现,重复的编号都是我自己输入资料编号的最大值,不是整个资料库的
: 问题2:整个网页重新整理以後就好了
大部份 LaPass 大大 都讲完了 :Q
会有这个状况简单来说,就是程式在执行上无法作到资源独占这件事,
不单是 DB,只要是任何有资源取用 / 异动的地方永远都会有这个问题。
你可以把这个档案 copy 一次,
在其中一个档案里的 insert 前 sleep 个 60 秒然後两只一起送出看看,
撞 key 是非常容易的 XD
##
要能确保资源独占,一是极小化(或着该说是极快化)程式的存取,
让在自己从存取到异动的过程里不会遇到别人,实际上这种很难有保障
以你的例子而言,是可以尝试把东西转成一道 sql 喂进去,像这样:
$A = date("md") ;//变数A:9开头加上带零的月、日
$B = substr(date('Y'),3,1);//变数B:取西元年第3个字元後1码
$C = Sprintf("9$B$A%s",'001') ; //变数B前加9,变数A後加001
// 以上你原本的 code 我不动
$D = "9$B$A"; // 我需要这个 :P
mysql_select_db($database_AdvList, $AdvList);
$sql =
" INSERT INTO `advlist` (`advID`) ".
" SELECT IF(`advID`<'$C', '$C',".
" CONCAT('$D', LPAD(RIGHT(`advID`, 3)+1, 3, '0')))".
" FROM `advlist` ORDER BY `advID` DESC LIMIT 1";
// 用 INSERT SELECT 来做,
// 如果拿到的最後一笔 advID 比今天的第一笔要小,就给值今天第一笔
// 如果最後一笔大於 / 等於今天的第一笔,则取末三位+1,再补零塞回去
当然这无法在 mysql 自己都很慢的时候还保证不撞 key…
##
资源独占另一种就是 lock,只要能确定「在我使用的期间,别人不可以动」,
那麽就能作到确保资源独占,
mysql 本身有 lock table 的语法
http://dev.mysql.com/doc/refman/5.0/en/lock-tables.html
如果你要比较高的保障,用 lock 一定是最有效的,
但是在大量瞬间多人写入的时候会有较长的 waiting(因 DB lock 页面开不起来)
或着我建议…这种不是很重要的序列编码,应该是由 auto increment 来处理掉,
然後看是要另外开一个 field / table 负责存每天第一笔的差值(其实也不需要)
还是怎样的… XD
--
※ 发信站: 批踢踢实业坊(ptt.cc)
◆ From: 1.161.193.130