1订单号是什么?
它是您在购物网站购物后获得的订单号,记录的是购物订单信息;在您需要与购物网站进行订单查询等操作时,需要给购物网站提供商家订单号。
2几种常见下单途径?
- Web网站下单。
- 打电话到呼叫中心(CallCenter)下单。
- 手机Wap下单。
如果采用常见的单数据库来存储的话,随着订单量的增加,单库的写压力增大,造成数据库服务器性能下降。一般会采用分库来缓解数据库服务器的压力。
有的同学可能会问:怎么来进行分库呢?
Web来源订单,存入Web订单库;CallCenter来源订单,存入CallCenter订单库;Wap来源订单,存入Wap订单库;最终,将这三种类型的数据库同步到订单主库中。
那么,问题来了,怎么把不同的订单同步到订单主库呢?
这里就引出了文章的主题订单号。电商网站一般利用订单号来作为订单表的主键;因此,我们必须保证订单号不重复,才能将订单安全的同步到订单主库中。
3订单命名规定
- 唯一性
这个大家都明白,主要保证订单号不重复。
- 安全性
订单编号不能透露你公司的真实运营信息,比如你的订单就是流水号的话,那么别人就可以从订单号推测出你公司的整体运营概括了。所以订单编码必须是除了你们公司少部分人外,其他人基本看不懂的。可以参考京东和淘宝的编码规则。
- 不能使用大规模随机码
因为大规模的随机码随机生成,因为本身就没有意义所以无所谓泄密了。但是事实上这种编码规则在实现上会有很大问题的。随机码满足第二点安全性要求,为了满足唯一性,那就得在生成随机码的时候对比历史数据是否有重复,如果你的订单数量到达了十万次,你每次生成订单编码时就得对比十万条历史数据。
这里有同学可能会问:随机码就不能在编码中使用了吗?
小规模的随机码是可以使用的,比如2~3位,这种随机码一般都是和流水号等结合使用,主要作用是为了隐藏流水号的真实数据而进行使用的。
- 防止并发
主要针对编码中有时间的设定。
- 控制位数
订单号的作用就是便于查询。一般正常使用场景应该是订单出异状或者退货的时候,用户将订单号报给客服,由客服进行查询。所以一般在10~15位为好。目前京东11位,淘宝16位。
4怎么保证订单号的唯一性?
作者在此,提供两种思路供大家参考。
- 订单号命名规则来生成
比如:业务编码 + 时间戳 + 机器编号[前4位] + 随机4位数 + 毫秒数。
说明:业务编码(OrderType: Web=1 CallCenter=2 Wap=3) 机器编号(用来表示由那台服务器生成的订单)
见伪代码,如下:
import org.apache.commons.lang3.RandomStringUtils; public static String genOrderNo(OrderType type){ Date curDate = new Date(); String orderType = getType(type); String dateStr4yyyyMMddHHmmss = new SimpleDateFormat("yyyyMMddHHmmss").format(curDate); String dateStr4SSS = new SimpleDateFormat("SSS").format(curDate); String random = RandomStringUtils.random(4,false,true); String machineCode = getMachineCode().substring(0,4); return orderType+dateStr4yyyyMMddHHmmss+machineCode+random+dateStr4SSS; }
技术上没有一本万利的方法,这种方法也有缺点的,这种方式在高并发下会频繁更新订单量记录表,很容易产生锁表。但是锁表问题也是可以解决的,加一层缓存。
- 全局订单号数据池来生成
数据库创建一个订单号数据库表(order_id_generator);利用python脚本生成一批订单号,将这批订单号存入到order_id_generator表中。生成订单时,会首先调用事务GET_ORDER_ID_FOR_REGISTER,获得当前订单号,再生成订单。这样就保证了子库订单号不会重复。
数据库代码如下:
CREATE TABLE `order_id_generator` ( `RANDOM_VALUE` bigint(20) NOT NULL, `ORDER_ID` int(11) NOT NULL, PRIMARY KEY (`RANDOM_VALUE`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; DROP PROCEDURE IF EXISTS `GET_ORDER_ID_FOR_REGISTER`; DELIMITER ;; CREATE DEFINER=`root`@`%` PROCEDURE `GET_ORDER_ID_FOR_REGISTER`() BEGIN declare userMid int default 0; declare randomValue bigint default 0; start transaction; select ORDER_ID, RANDOM_VALUE into orderId, randomValue from order_id_generator limit 1 for update; if userMid > 0 then delete from order_id_generator where RANDOM_VALUE = randomValue; end if; commit; select orderId from dual; END ;; DELIMITER ;
伪代码如下:
/** * 得到一个订单号。 * * @return */ Long getIdForOrder();
总结:订单号的生成方案,需要根据目前的订单量而定;因为任何方案都有自己特定的业务场景。