雪花算法生成唯一ID PHP版
由于最近对老的项目维护出现了订单编号重复的记录;所以对这块优化一下:雪花算法生成唯一ID;具体大家可以详细了解一下其核心思想;利用雪花算法生成了1000万条ID记录;未出现重复记录;实现过程如下,已测试验证过:
循环生成1000万条记录:
namespace App\Http\Controllers\Api;
use App\Lib\SnowFlake;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
class SnowFlakeController extends Controller
{
/**
* https://www.jianshu.com/p/fdebbb0ea785
* 雪花算法 生成唯一id
* @return \Illuminate\Http\JsonResponse
*/
public function snowFlakeId()
{
set_time_limit(0);
ini_set('memory_limit', '2048M');
//可批量插入
$snowFlake = new SnowFlake;
for($i = 0; $i < 10000000; $i++){
$snow_flake_id = "";
$snow_flake_id = $snowFlake->nextId();
\DB::table('snow_flake_bak')->insert(['snow_flake_id' => $snow_flake_id]);
}
echo 'done--'.$i;die;
}
}
生成代码:
namespace App\Lib;
/**
* 雪花算法 生成唯一ID
* Class Base62Convert
* @package App\Lib
*/
class SnowFlake
{
//开始时间,固定一个小于当前时间的毫秒数即可
const twepoch = 1474992000000;//2016/9/28 0:0:0
//机器标识占的位数
const workerIdBits = 10;
//毫秒内自增数点的位数
const sequenceBits = 12;
protected $workId = 0;
//要用静态变量
static $lastTimestamp = -1;
static $sequence = 0;
function __construct($workId = 1){
//机器ID范围判断
$maxWorkerId = -1 ^ (-1 << self::workerIdBits);
if($workId > $maxWorkerId || $workId< 0){
throw new Exception("workerId can't be greater than ".$maxWorkerId." or less than 0");
}
//赋值
$this->workId = $workId;
}
//生成一个ID
public function nextId(){
$timestamp = $this->timeGen();
$lastTimestamp = self::$lastTimestamp;
//判断时钟是否正常
if ($timestamp < $lastTimestamp) {
throw new Exception("Clock moved backwards. Refusing to generate id for %d milliseconds", ($lastTimestamp - $timestamp));
}
//生成唯一序列
if ($lastTimestamp == $timestamp) {
$sequenceMask = -1 ^ (-1 << self::sequenceBits);
self::$sequence = (self::$sequence + 1) & $sequenceMask;
if (self::$sequence == 0) {
$timestamp = $this->tilNextMillis($lastTimestamp);
}
} else {
self::$sequence = 0;
}
self::$lastTimestamp = $timestamp;
//
//时间毫秒/数据中心ID/机器ID,要左移的位数
$timestampLeftShift = self::sequenceBits + self::workerIdBits;
$workerIdShift = self::sequenceBits;
//组合3段数据返回: 时间戳.工作机器.序列
$nextId = (($timestamp - self::twepoch) << $timestampLeftShift) | ($this->workId << $workerIdShift) | self::$sequence;
return $nextId;
}
//取当前时间毫秒
protected function timeGen(){
$timestramp = (float)sprintf("%.0f", microtime(true) * 1000);
return $timestramp;
}
//取下一毫秒
protected function tilNextMillis($lastTimestamp) {
$timestamp = $this->timeGen();
while ($timestamp <= $lastTimestamp) {
$timestamp = $this->timeGen();
}
return $timestamp;
}
}
1000万数据无重复记录
记录数据:
总条数:
生成18位的随机数字;可根据实际需要前后加入英文字符等;工作中的日常可拿来封装后即用;