最近在研发区块链支付系统,众所周知,有支付必有订单。今天不做支付系统的具体分析,只来谈谈目前较为热门的订单号码生成方案!
在分布式高并发情况下,订单号必须满足最重要的一个条件:唯一性,订单关系这支付明细,与支付相关的向来都是最重要的,马虎不得。
目前较为成熟的,我所知道的有两种生成方案,接下来做一下对比:
1、根据MySQL自增主键生成订单号
首先,需要创建一张满足自增条件的表,有两个字段即可,id和value,id设置为自增,类型为bigint即可
eg:在mybatis框架中
<insert id="insertAndGetId" useGeneratedKeys="true" keyProperty="id" parameterType="com.chenzhou.mybatis.User"> insert into user(userName,password,comment) values(#{userName},#{password},#{comment}) </insert>
其中useGeneratedKeys="true" 的配置就表示新增后返回主键id,此时我们就可以根据主键id做订单唯一性标识,再加上时间201903010+自增主键,或其他复杂的组合方式即可
此方式的优点:关系型数据库的可靠性!
此方式的缺点:在分布式环境下,需要保证新增的操作是单线程的,需要加锁。
2、利用Redis非关系型数据库
先看代码,再解释
public String getOrderId(String prefix) { //生成订单号 redis incr SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd"); String time = sdf.format(new Date()); //当天流水7位 Long tx = redisTemplate.opsForValue().increment(CommonConstants.OUR_ORDER_ID_INCREMENT_KEY, 1); if (tx < CommonConstants.ORDER_ID_INCREMENT_DEFAULT_VALUE) { //没值,自动添加 redisTemplate.opsForValue().set(CommonConstants.OUR_ORDER_ID_INCREMENT_KEY, CommonConstants.ORDER_ID_INCREMENT_DEFAULT_VALUE); tx = redisTemplate.opsForValue().increment(CommonConstants.OUR_ORDER_ID_INCREMENT_KEY, 1); } //自动补0 String end = autoAddZero(String.valueOf(tx)); return prefix + time + end; } public String autoAddZero(String liuShuiHao) { Integer intHao = Integer.parseInt(liuShuiHao); DecimalFormat df = new DecimalFormat(CommonConstants.ORDER_ID_NUM); return df.format(intHao); }
getOrderId方法,传入参数prefix,这是订单前缀,有时候我们需要为不同种类或功能生成不一样的订单前缀以助区分,其中最主要是用到了redis的incr函数。我们都知道redis是单行程的,每次操作都不会引发脏读的问题因此,我们可以利用redis的自增方法incr为我们的订单做唯一性处理。
tx < CommonConstants.ORDER_ID_INCREMENT_DEFAULT_VALUE 的判断是由于第一次调用是没有值的,需要设置一个初始值
autoAddZero是我写的辅助保持订单长度一致的方法,剩下的大写的都是常量,根据字面意思设置即可 此方法的优点:基于缓存策略的性能上明显提升。此方法的缺点:redis数据需要载入硬盘,防丢失(其实也不算缺点) 如有不妥,欢迎指正!
原文地址:https://www.cnblogs.com/tc520/p/10457977.html
时间: 2024-11-09 02:03:29