2018年8月10日08:53:50
一般生产订单号的方式
1,使用时期+随机数1+随机数2
缺点,有可能在并发的时候会出现重复,解决办法就是加唯一索引,在插入数据的做查询是否已经被使用
2,使用时间+统计当前订单数,按订单数+1,很多系统使用这种
缺点,如果有需要删除数据,当然脑残的需求,但是还是会有,再次下单就会出现订单重复,这种非常不好改动
参考1:金蝶k3,会有一个全局使用的ID,通过触发器增长
参考2:经验之谈,全局计数器解决2个根本问题,订单号不重复,使用一次请求一次,返回最近的计算结果,2不会因为删除订单出现订单号重复
数据库
--计数器表
CREATE TABLE `counter` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,`name` varchar(100) DEFAULT NULL COMMENT ‘名称‘,`value` bigint(20) unsigned DEFAULT ‘1‘ COMMENT ‘存储的值‘,`create_time` datetime NOTNULL DEFAULT ‘0000-00-00 00:00:00‘ COMMENT ‘创建时间‘,`update_time` datetime NOTNULL DEFAULT ‘0000-00-00 00:00:00‘ COMMENT ‘更新时间‘,`tag` varchar(50) DEFAULT NULL COMMENT ‘标签‘,`type` tinyint(1) NOT NULL DEFAULT ‘10‘ COMMENT ‘类型10采购订单20销售订单30自营物流号‘,PRIMARYKEY(`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT=‘计数器表‘;
注意我存储的 value是bigint 20,足够大
//计数器
public static function counter($type = null) {if (empty($type)) {throw new \Exception(‘tag标签不能为空‘);
}$now = time();$time = date(‘Ymd‘, $now);$time1 = date(‘Ym‘, $now);$tag = self::counter_array($type);$name = $time . ‘_‘ . $tag;
DB::beginTransaction();try{$Counter = Counter::where(‘name‘, $name)->lockForUpdate()->first([‘value‘, ‘id‘]);if (empty($Counter)) {//没有就插入
$Counter = newCounter;$Counter->name = $name;$Counter->type = $type;$Counter->tag = $tag;$Counter->save();$Counter = Counter::where(‘name‘, $name)->first([‘value‘, ‘id‘]);
}$Counter = $Counter->toArray();//加锁 防止生成的订单号出错,没有在name上加索引
Counter::where(‘id‘, $Counter[‘id‘])->lockForUpdate()->first();if ($type == 40) {$new_count = (float) $Counter[‘value‘] + 1;
Counter::where(‘name‘, $name)->update([‘value‘ => $new_count]);$string = $time1 . str_pad($new_count, 6, ‘0‘,STR_PAD_LEFT);
}else{$new_count = (float) $Counter[‘value‘] + 3;
Counter::where(‘name‘, $name)->update([‘value‘ => $new_count]);$string = $time . str_pad($new_count, 12, ‘0‘,STR_PAD_LEFT);
}
DB::commit();return $string;
}catch (\Exception $e) {
DB::rollBack();throw new \Exception($e->getMessage());
}
}//订单计数器映射数组
public static function counter_array($type = null) {//采购订单号
$array[‘10‘] = ‘sales_order_number‘;//销售订单号
$array[‘20‘] = ‘purchase_order_number‘;//自营物流订单号
$array[‘30‘] = ‘logistics_order_number‘;//入库订单号
$array[‘40‘] = ‘inbound_order_number‘;//出库订单号
$array[‘50‘] = ‘outbound_order_number‘;if (empty($type)) {return $array;
}return $array[$type];
}
解释一下为什么不适用 全局订单不是+1而是+3,防止有特殊订单需要插入,同时不让计数器的数字增长太快
还有必须加锁,虽然有事务,但是还是要加锁,订单长度自己选择填充长度,我定义的是20个长度,足够了14位长度的除以3的长度,足够了
有人会担心新能,我只能说你想多了,这点压力都扛不住,不可能,见过随时写入mysql,随时读取的操作吗?这么糙的逻辑代码mysql都能满足
原文:https://www.cnblogs.com/zx-admin/p/9452952.html