PHP MYSQL 防止在同时从不同用户插入时获取重复的唯一 ID


PHP MYSQL prevent getting duplicate unique id while inserting from different users at same time

>我正在尝试在每张发票中生成发票ID,现在我有数千张发票,现在从不同的IP添加同时我得到重复的发票ID如何防止它,

通过获取上次插入的发票 ID 并向其递增 1 来生成发票 ID。

我的函数如下参数

get_new_tbl_id('table_name','invoice_id_column','string to strip (INV in INV0012)','any conditions');
function get_new_tbl_id($tbl_name,$id_field,$string,$options='')
{
$new_id = 0;
$query_count_rows = "SELECT MAX(CONVERT(replace(replace($id_field,',',''),'$string',''), SIGNED INTEGER)) as $id_field FROM $tbl_name WHERE $id_field LIKE '$string%'  $options";
$count_rows = mysql_query($query_count_rows);
$num_rows = mysql_num_rows($count_rows);
if($num_rows >0)
{
$last_row = mysql_fetch_assoc($count_rows);
$last_id = $last_row[$id_field];
$last_inserted_id = intval(str_replace($string,'',$last_id));
$new_id = $last_inserted_id+1;
}
else
$new_id = 1;
$format = '%1$03d';
$new_id=sprintf($format,$new_id,'');
return $string.$new_id;
}

我的表格如下

CREATE TABLE IF NOT EXISTS `tbl_invoice` (
  `invoice_tbl_id` int(11) NOT NULL AUTO_INCREMENT,
  `invoice_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  `invoice_ip` varchar(25) NOT NULL,
  `invoice_status` tinyint(1) NOT NULL DEFAULT '0',
  `invoice_added_by` smallint(6) NOT NULL,
  `invoice_edited_by` smallint(6) NOT NULL,
  `invoice_date` date NOT NULL,
  `invoice_id` varchar(15) NOT NULL,
  `customer_id` varchar(11) NOT NULL,
  `invoice_credit_date` tinyint(4) NOT NULL,
  `invoice_credit_status` tinyint(1) NOT NULL DEFAULT '0',
  `total_items_count` smallint(6) NOT NULL,
  `invoice_total_amount` varchar(20) NOT NULL,
  `invoice_grandtotal_amount` double NOT NULL,
  `invoice_discount` double NOT NULL DEFAULT '0',
  `invoice_total_card_amount` double NOT NULL,
  `invoice_total_cash_amount` double NOT NULL,
  `invoice_total_profit` varchar(10) NOT NULL,
  `cashier_approval` tinyint(1) NOT NULL DEFAULT '0',
  `cashier_approval_id` smallint(6) NOT NULL,
  `cashier_approval_time` datetime NOT NULL,
  `cashier_approval_ip` varchar(20) NOT NULL,
  `invoice_delete_note` text NOT NULL,
  PRIMARY KEY (`invoice_tbl_id`),
  KEY `invoice_id` (`invoice_id`)
) ENGINE=InnoDB  DEFAULT CHARSET=latin1

使用 myisam 表为您生成包含 2 个字段的 ID。第一个字段包含前缀(这在您的函数中$string),第二个字段应该是自动增量字段。在这两个字段上添加主键,但前缀字段必须是索引中的第一个字段。如果您在此表中插入带有前缀的新行,则 mysql 将递增该组中的自动增量值。

有关详细信息和示例,请参阅 mysql 文档中有关自动增量的 myisam 注释部分。

CREATE TABLE animals (
    grp ENUM('fish','mammal','bird') NOT NULL,
    id MEDIUMINT NOT NULL AUTO_INCREMENT,
    name CHAR(30) NOT NULL,
    PRIMARY KEY (grp,id)
) ENGINE=MyISAM;
INSERT INTO animals (grp,name) VALUES
    ('mammal','dog'),('mammal','cat'),
    ('bird','penguin'),('fish','lax'),('mammal','whale'),
    ('bird','ostrich');

如果你的基表是 mysql,那么只需更改它以获得这种行为,如果不是,那么创建一个单独的 myisam 表,先插入到那个表中,然后获取主表中使用的 ids。

可能会有一些优化的解决方案,但现在我可以给你这个解决方案

如果一个人正在获取 ID $lock=true 并使用 static variable lock 保持其他请求等待 1 秒,然后通过 goto start; 再次检查,直到第一个请求完成;最后 make $lock=false; 以释放该功能。

public static $lock=false;
function get_new_tbl_id($tbl_name,$id_field,$string,$options='')
{
    global $lock;
    start:
    if($lock==true){
        sleep(1);
        goto start;
    }
    if($lock==false){
        $lock==true;
    }
    $new_id = 0;
    $query_count_rows = "SELECT MAX(CONVERT(replace(replace($id_field,',',''),'$string',''), SIGNED INTEGER)) as $id_field FROM $tbl_name WHERE $id_field LIKE '$string%'  $options";
    $count_rows = mysql_query($query_count_rows);
    $num_rows = mysql_num_rows($count_rows);
    if($num_rows >0)
    {
    $last_row = mysql_fetch_assoc($count_rows);
    $last_id = $last_row[$id_field];
    $last_inserted_id = intval(str_replace($string,'',$last_id));
    $new_id = $last_inserted_id+1;
    }
    else
    $new_id = 1;
    $format = '%1$03d';
    $new_id=sprintf($format,$new_id,'');
    $lock=false;
    return $string.$new_id;
}