mall--no.1

最新目标,除了看技术文档之外。

把从码云上 电商(mall) 项目代码看懂。

留此纪念。看的一些随想都记录到此。

 

2020-1-29 凌晨00:46

 

首先看了后台接口,比如说查询商品。直接上代码:

 

 

list传具体实现是直接sql语句查询数据库,这在商品单一,且商品比较少的情况下是没问题的,但,如果放到淘宝,京东上面呢?

很明显查询商品不光是前台,后台起码也来一个搜索引擎吧?! 

 

 如图,查询出来结果。

本来想睡觉但,无意间看到mall 系统中18位订单号生产但规则,直接上代码:

 

 

咋一看,很聪明,利用redis单线程的特点,每次递增,做到订单号无重复。

但我们来想一想,redis如果有多台(集群),且高并发但情况下。能保证唯一么?

其实,集群分片的话也是可以的,但查阅资料,RedisAtomicLong这个类用但比较多。你们可以相互比较一下。

参考https://zhuanlan.zhihu.com/p/95814245

代码贴一下,防止失效。

@Resource
private RedisTemplate<String,Serializable> redisTemplate;

/**
* 获取有过期时间的自增长ID
* @param key
* @param expireTime
* @return
*/
public long generate(String key,Date expireTime) {
RedisAtomicLong counter = new RedisAtomicLong(key, redisTemplate.getConnectionFactory());
Long expire = counter.getExpire();
if(expire==-1){
counter.expireAt(expireTime);
}
return counter.incrementAndGet();
}


public String generateOrderId() {
//生成id为当前日期(yyMMddHHmmss)+6位(从000000开始不足位数补0)
LocalDateTime now = LocalDateTime.now();
String orderIdPrefix = getOrderIdPrefix(now);//生成yyyyMMddHHmmss
String orderId = orderIdPrefix+String.format("%1$06d", generate(orderIdPrefix,getExpireAtTime(now)));
return orderId;

}

public static String getOrderIdPrefix(LocalDateTime now){
return now.format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"));
}

public Date getExpireAtTime(LocalDateTime now){
ZoneId zoneId = ZoneId.systemDefault();
LocalDateTime localDateTime = now.plusSeconds(20);
ZonedDateTime zdt = localDateTime.atZone(zoneId);
Date date = Date.from(zdt.toInstant());
return date;
}

思路:日期(yyyyMMddHHmmss)+redis原子生成的数字(不足6位前面补0)

类似:20191206221953000001

理论上6位后缀支持每秒最多生成999999个订单号,具体可以根据业务调整日期格式或日期后面的位数。核心在于对象RedisAtomicLong (可以想下juc包下的AtomicLong),它对于同一个key会一直自增生成数字,这里我设置的key过期时间为20s,减轻redis的压力。

RedisAtomicLong的incrementAndGet方法源码,看下能大致明白,对于每个不同的key每次自增1,这个是由redis天然单线程保证的,一般不会出现重复的情况。

 

其实要生产唯一id,还有雪花算法

基于雪花算法snowflake 生成全局id,本地生成,没有网络开销,效率高,但是依赖机器时钟。大家可以去看下实现方式。

posted on 2020-01-28 00:48  Jason_LZP  阅读(135)  评论(0)    收藏  举报