場景描述: 表t2 中 有 自增主鍵 id 和 字段v 當插入記錄的時候 要求 v與id 的值相等(按理來說這樣的字段是需要拆表的,但是業務場景是 只有某些行相等 )
在網上搜的一種辦法是 先獲取自增ID
SELECT max(id)+1 from t2
然後給v字段插入獲取到的值
但是這樣的做法在有刪除行+調整過自增值的表中是不准確的
於是換個思路 從 information_schema 下手 讀取表的信息
INSERT INTO `t2` VALUES ( NULL, ( SELECT `AUTO_INCREMENT` FROM `information_schema`.`TABLES` WHERE `TABLE_SCHEMA` = 'test' AND `TABLE_NAME` = 't2' ) );
功能是實現了 但是真的安全麼
於是寫個PHP文件
1 <?php 2 $sql = "INSERT INTO `t2` VALUES(NULL ,(SELECT `AUTO_INCREMENT` FROM `information_schema`.`TABLES` WHERE `TABLE_SCHEMA` = 'test' AND `TABLE_NAME`='t2'));"; 3 4 $link = mysql_connect("localhost", "root", "") or die("Could not connect: " . mysql_error()); 5 mysql_select_db("test"); 6 mysql_query($sql); 7 mysql_close($link); 8 ?>
用ab工具測試
ab -n 50000 -c 20 http://localhost/my.php
結果是:大量的行出現了 v 和 id 不相等的情況(select * from t2 where id != v;)
改寫下 PHP
1 <?php 2 $sql = "INSERT INTO `t2` VALUES(NULL ,(SELECT `AUTO_INCREMENT` FROM `information_schema`.`TABLES` WHERE `TABLE_SCHEMA` = 'test' AND `TABLE_NAME`='t2'));"; 3 4 $link = mysql_connect("localhost", "root", "") or die("Could not connect: " . mysql_error()); 5 mysql_select_db("test"); 6 mysql_query('START TRANSACTION'); #開始事務 7 mysql_query($sql); 8 $id = mysql_insert_id(); 9 $res = mysql_query("SELECT `v` FROM `t2` WHERE id= ".$id); 10 11 if (!$res) { 12 mysql_close($link); 13 die; 14 } 15 16 $row = mysql_fetch_assoc($res); 17 if($row['v'] != $id){ 18 mysql_query(' ROLLBACK '); #回滾事務 19 } 20 mysql_query('COMMIT'); #提交事務 21 mysql_close($link); 22 ?>
再使用AB測試,這次速度變慢了 但是結果是都是正確的