Authored by chenchao

use database config control sequence of order code

package com.yohoufo.order.model.dto;
import lombok.Data;
/**
* Created by chao.chen on 2019/3/8.
*/
@Data
public class OrderCodeRule {
private String env;
}
... ...
... ... @@ -70,7 +70,9 @@ public class CacheKeyBuilder {
SELLER_EARNEST_MONEY_CONFIG("ufo:order:seller:earnestMoney:config",""),
PRESALE_THRESHOLD("ufo:order:presale:threshold", "")
PRESALE_THRESHOLD("ufo:order:presale:threshold", ""),
ORDER_CODE_RULE("ufo:order:code:rule", "")
;
private String fix;
... ...
... ... @@ -12,6 +12,7 @@ import com.yohoufo.dal.order.MetaConfigMapper;
import com.yohoufo.dal.order.model.MetaConfig;
import com.yohoufo.order.model.dto.BuyerPenalty;
import com.yohoufo.order.model.dto.EarnestMoney;
import com.yohoufo.order.model.dto.OrderCodeRule;
import com.yohoufo.order.model.dto.PreSaleOrderConfig;
import com.yohoufo.order.service.cache.CacheKeyBuilder;
import com.yohoufo.order.service.cache.ExpiredTime;
... ... @@ -247,4 +248,22 @@ public class MetaConfigService {
return psoc;
}
/**
* 获取配置的订单号生成规则
* @return
*/
public OrderCodeRule getOrderCodeRule(){
CacheKeyBuilder.KeyTemp kt = CacheKeyBuilder.KeyTemp.ORDER_CODE_RULE;
RedisKeyBuilder rkb = kt.builderKeyOnlyFixed();
final String key = MetaConfigKey.ORDER_CODE_RULE;
String configVal = new DataProcesser(rkb, key, ExpiredTime.ORDER_BASE_CONFIG).getConfigVal();;
OrderCodeRule ocr = new OrderCodeRule();
try{
ocr = JSONObject.parseObject(configVal, OrderCodeRule.class);
}catch (Exception ex){
logger.warn("in getOrderCodeRule parseObject fail, metaVal {}", configVal, ex);
}
return ocr;
}
}
... ...
package com.yohoufo.order.service.support.codegenerator.impl;
import com.yohobuy.ufo.model.order.common.OrderCodeType;
import com.yohobuy.ufo.model.order.constants.OpsEnv;
import com.yohoufo.order.model.dto.OrderCodeRule;
import com.yohoufo.order.service.impl.MetaConfigService;
import com.yohoufo.order.service.support.codegenerator.OrderCodeGenerator;
import com.yohoufo.order.service.support.codegenerator.bean.CodeBitMeta;
import com.yohoufo.order.service.support.codegenerator.bean.CodeMeta;
... ... @@ -31,6 +34,9 @@ public class OrderCodeGeneratorImpl implements OrderCodeGenerator {
@Autowired
MachineIdProvider machineIdProvider;
@Autowired
MetaConfigService metaConfigService;
long machineId = 0l;
@PostConstruct
... ... @@ -41,7 +47,13 @@ public class OrderCodeGeneratorImpl implements OrderCodeGenerator {
}
if (idPopulator == null){
idPopulator = new AtomicIdPopulator();
SequenceStrategy.SingleData sssd = createSequence();
long seq = sssd.start;
AtomicIdPopulator.Variant variant = new AtomicIdPopulator().new Variant(seq);
idPopulator = new AtomicIdPopulator(variant);
}
machineId = machineIdProvider.getMachineId();
... ... @@ -50,6 +62,31 @@ public class OrderCodeGeneratorImpl implements OrderCodeGenerator {
validateMachineId(this.machineId);
}
private SequenceStrategy.SingleData createSequence(){
OrderCodeRule ocr = metaConfigService.getOrderCodeRule();
Long seq = 0L;
String env = null;
boolean envIsNull = false;
if (ocr==null || (envIsNull = ((env=ocr.getEnv()) == null))){
log.warn("in order code generator env use prd, OrderCodeRule {}", ocr);
}
//明确指定了配置使用非生产环境时,序列号从1000开始
if (!envIsNull && !OpsEnv.PRD.getName().equalsIgnoreCase(env)){
seq = 1000L;
log.info("in order code generator env use not prd config, OrderCodeRule {} seq {}", ocr, seq);
}
log.info("in order code generator init config, OrderCodeRule {} seq {}", ocr, seq);
/*
*这是常驻内存的方式,其实很不妥,运维不方便;
* 数据库修改后需要重新发布工程才能获取新值
*/
SequenceStrategy.SingleData sssd = SequenceStrategy.SingleData.create(env, seq);
return sssd;
}
public long generate(OrderCodeType type) {
CodeMeta id = new CodeMeta();
... ...
package com.yohoufo.order.service.support.codegenerator.impl;
import lombok.Getter;
import lombok.ToString;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
/**
* Created by chao.chen on 2019/3/11.
*/
@Service
public class SequenceStrategy {
private final static Logger logger = LoggerFactory.getLogger(SequenceStrategy.class);
public static final long DEFAULT_SEQ = 0L;
@ToString
public static class SingleData{
@Getter
String env;
@Getter
long start;
private static SingleData data;
static SingleData create(String env, long start){
if (data == null){
synchronized (SingleData.class){
if (data == null){
data = new SingleData();
data.env = env;
data.start = start;
}
}
}
return data;
}
}
public static SingleData getStart(){
SingleData sd = SingleData.data;
logger.info("in get order code generator obtain seq Start {}", sd);
return sd;
}
}
... ...
... ... @@ -3,6 +3,7 @@ package com.yohoufo.order.service.support.codegenerator.populater;
import com.yohoufo.order.service.support.codegenerator.bean.CodeBitMeta;
import com.yohoufo.order.service.support.codegenerator.bean.CodeMeta;
import com.yohoufo.order.service.support.codegenerator.impl.SequenceStrategy;
import com.yohoufo.order.service.support.codegenerator.timer.SimpleTimer;
import java.util.concurrent.atomic.AtomicReference;
... ... @@ -12,15 +13,25 @@ import java.util.concurrent.atomic.AtomicReference;
*/
public class AtomicIdPopulator implements IdPopulator {
class Variant {
private long sequence = 0;
public class Variant {
private long sequence = SequenceStrategy.DEFAULT_SEQ;
private long lastTimestamp = -1;
public Variant(long sequence) {
this.sequence = sequence;
}
}
private AtomicReference<Variant> variant = new AtomicReference<Variant>(new Variant());
private AtomicReference<Variant> variant;
public AtomicIdPopulator() {
super();
variant = new AtomicReference<Variant>(new Variant(SequenceStrategy.DEFAULT_SEQ));
}
public AtomicIdPopulator(Variant variant) {
super();
this.variant = new AtomicReference<Variant>(variant==null ? new Variant(SequenceStrategy.DEFAULT_SEQ) : variant) ;
}
public void populateId(SimpleTimer timer, CodeMeta id, CodeBitMeta idBitMeta) {
... ... @@ -45,22 +56,31 @@ public class AtomicIdPopulator implements IdPopulator {
timestamp = timer.tillNextTimeUnit(varOld.lastTimestamp);
}
} else {
sequence = 0;
sequence = getSeqStart();
}
// Assign the current variant by the atomic tools
varNew = new Variant();
varNew.sequence = sequence;
varNew = new Variant(sequence);
//varNew.sequence = sequence;
varNew.lastTimestamp = timestamp;
if (variant.compareAndSet(varOld, varNew)) {
id.setSeq(sequence);
id.setTime(timestamp);
break;
}
}
}
public long getSeqStart(){
long sequence = SequenceStrategy.DEFAULT_SEQ;
SequenceStrategy.SingleData sssd = SequenceStrategy.getStart();
if (sssd!=null){
sequence = sssd.getStart();
}
return sequence;
}
}
... ...