• Mysql表中唯一编号的分配机制


    最近遇到一个问题:高并发环境下,如何避免MYSQL一张表里的某些列不要重复。

    同其他博友一样 https://blog.csdn.net/jacketinsysu/article/details/51526284 提出这个问题。

    方式一:使用Mysql自带的列唯一索引(Unique)

    可以在声明表的时候就加入这样一个约束(下面是mysql的语法):

    CREATE TABLE IF NOT EXISTS `test_orderno2` (
        `id` int unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID',
        `name` varchar(50) NOT NULL COMMENT '名称',
        `order_no` bigint unsigned NOT NULL COMMENT '编号',
        `createtime` int(10) unsigned NOT NULL DEFAULT 0 COMMENT '创建时间',
        PRIMARY KEY (`id`),
        UNIQUE KEY `uniq_order_no` (`order_no`),
        UNIQUE KEY `uniq_name` (`name`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT '测试编号';
    CREATE TABLE `test_orderno3` (
      `id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID',
      `order_no` bigint(20) unsigned NOT NULL COMMENT '自定义编号',
      `order_simple` char(21) NOT NULL COMMENT '简单编号',
      `order_complex` char(30) NOT NULL COMMENT '复杂编号',
      `createtime` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '创建时间',
      PRIMARY KEY (`id`),
      UNIQUE KEY `uniq_order_no` (`order_no`),
      UNIQUE KEY `uniq_order_simple` (`order_simple`),
      UNIQUE KEY `uniq_order_complex` (`order_complex`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='测试编号3';

    这里对  test_orderno2 表设置了两个列的唯一索引,在插入数据的同时会检查该表这两列是存在,存在则会抛出sql错误

    SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry '2018000001' for key 'uniq_order_no

    新增行的PHP代码如下:

    $count = $test_orderno2->count();
    
    $addData['name'] = implode( '',explode('.',uniqid('',true)) );
    $addData['order_no'] = sprintf( "2018%06s",++$count );
    $addData['createtime'] = time();
    
    $status = $test_orderno2->add($addData);
    $test_orderno3 = M('test_orderno3');
    $count = $test_orderno3->count();
    $addData['order_no'] = sprintf( "2018%06s",++$count );
    // 唯一性较高的唯一编号(21位)
    $system_no = uniqid();
    $system_no_date = date( 'YmdHis',hexdec(substr($system_no,0,8)) );
    $system_no_rand = sprintf( "%07s",hexdec(substr($system_no,8,5)) );
    $addData['order_simple'] = $system_no_date.$system_no_rand;
    // 唯一性高的唯一编号(30位)
    $system_no = implode( '',explode('.',uniqid('',true)) );
    $system_no_date = date( 'YmdHis',hexdec(substr($system_no,0,8)) );
    $system_no_rand = sprintf( "%07s",hexdec(substr($system_no,8,5)) );
    $more_entropy = substr($system_no,13,9);
    $addData['order_complex'] = $system_no_date.$system_no_rand.$more_entropy;
    $addData['createtime'] = time();
    // $this->ajaxReturn($addData);
    $status = $test_orderno3->add($addData);
    $this->ajaxReturn(array('status'=>$status));

    这样在高并发的时候只满足一个客户端请求,其他客户端请求全部会抛出sql错误。

    如果业务需求在高并发的时候要正常处理多个客户端请求成功,则不建议采用该方式

    方式二:使用PHP代码进行唯一编号的分配

    string uniqid ([ string $prefix = "" [, bool $more_entropy = false ]] )

    PHP函数 uniqid 生成唯一编号代码如下:

    /**
    * 获取一个带前缀、基于当前时间微秒数的唯一ID。
    */
    // 最简单的一种
    $uniqid = uniqid(); // => string '5b11088f3c40a' (length=13)
    // 添加前缀
    $uniqid = uniqid('j_'); // => string 'j_5b11088f3c40a' (length=15)
    // 设置combined linear congruential generator,使得唯一性更强
    $uniqid = uniqid('',true); // => string '5b11094264cd58.46100058' (length=23)

    了解到 uniqid 的使用,则可以根据该函数来做唯一列

    // 一行代码得到唯一列
    $uniqid = implode( '',explode('.',uniqid('',true)) ); // => string '5b1109c17228c598550406' (length=22)

    方式三:使用PHP代码进行唯一编号的分配,并分配是数字日期型

    直接上代码:

    1 // 1. 并发量高使用  22 (唯一性高)
    2 $system_no = implode( '',explode('.',uniqid('',true)) );
    3 var_dump( $system_no );
    4 $system_no_date = date( 'YmdHis',hexdec(substr($system_no,0,8)) );
    5 $system_no_rand = sprintf( "%07s",hexdec(substr($system_no,8,5)) );
    6 $more_entropy = substr($system_no,13,9);
    7 // var_dump( $system_no_date."-".$system_no_rand."-".$more_entropy );
    8 var_dump( $system_no_date.$system_no_rand.$more_entropy );

    line.2-------------得到方式二中的22位唯一字符串

    line.4-------------将22中前8位取出,经过研究发现前8既然是当前时间戳16进制,所以根据公式可以得出当前时间戳的YmdHis格式

    line.5-------------随后又出去8位到13位,经过研究发现这5位也是16进制,想转化成数字需要锁定FFFFF的值=1048575,最大7位,则使用%07s不足7位则前面补0保持7位

    line.6-------------最后还剩下9位数字是为了增加唯一性的,则不用理会

    line.8-------------30位的日期型唯一编号便出炉了

    1 // 2. 通常返回  13 (唯一性较高)
    2 $system_no = uniqid();
    3 var_dump( $system_no );
    4 $system_no_date = date( 'YmdHis',hexdec(substr($system_no,0,8)) );
    5 $system_no_rand = sprintf( "%07s",hexdec(substr($system_no,8,5)) );
    6 // var_dump( $system_no_date."-".$system_no_rand );
    7 var_dump( $system_no_date.$system_no_rand );

    line.2-------------得到方式二中的13位唯一字符串

    line.4-------------将22中前8位取出,经过研究发现前8既然是当前时间戳16进制,所以根据公式可以得出当前时间戳的YmdHis格式

    line.5-------------随后又出去8位到13位,经过研究发现这5位也是16进制,想转化成数字需要锁定FFFFF的值=1048575,最大7位,则使用%07s不足7位则前面补0保持7位

    line.7-------------21位的日期型唯一编号便出炉了

  • 相关阅读:
    phpcms V9实现QQ登陆OAuth2.0
    PHP程序员的技术成长规划(送给迷茫的你)
    php实现冒泡排序
    php实现堆排序
    网络抓包以及进行简单数据分析
    网络编程之套接字(tcp)
    网络编程之套接字(udp)
    C语言之位运算
    linux线程及互斥锁
    嵌入式常用英文缩写及单词整理
  • 原文地址:https://www.cnblogs.com/jiangxiaobo/p/9122574.html
Copyright © 2020-2023  润新知