fix:微服务多实例下单号重复的问题

yun-zuoyi
汪云昊 5 years ago
parent c146b3b52e
commit a67f6b6918

@ -3,6 +3,8 @@ package cn.estsh.i3plus.core.api.iservice.base;
import cn.estsh.i3plus.pojo.platform.bean.SysOrderNoRule;
import io.swagger.annotations.ApiOperation;
import java.util.List;
/**
* @Description :
* @Reference :
@ -20,4 +22,12 @@ public interface ISynchronizedService {
@ApiOperation(value = "根据code查询最新单号规则")
SysOrderNoRule nextOrderNo(String code);
/**
*
* @param code
* @return
*/
@ApiOperation(value = "根据code查询最新单号规则")
List<SysOrderNoRule> nextOrderNo(String code, int num);
}

@ -64,6 +64,14 @@ public interface ISysOrderNoRuleService {
SysOrderNoRule doGetSysOrderNoRuleCode(String code);
/**
*
* @param code
* @return
*/
@ApiOperation(value = "根据code查询最新单号规则")
List<SysOrderNoRule> doGetSysOrderNoRuleByCodeAndNum(String code,int num);
/**
* id
* @param id ID
* @param status

@ -38,6 +38,12 @@ import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.stream.Collectors;
import static cn.estsh.i3plus.platform.common.util.CommonConstWords.REDIS_PREFIX_LOCK_BATCH_GET_ORDER_NO;
import static cn.estsh.i3plus.platform.common.util.CommonConstWords.REDIS_PREFIX_LOCK_GET_ORDER_NO;
/**
* @Description :
@ -63,6 +69,9 @@ public class WhiteController extends CoreBaseController {
private ISystemLoginService systemLoginService;
@Autowired
private ISysOrderNoRuleService sysOrderNoRuleService;
@Autowired
private ISysUserService userService;
@Autowired
@ -92,7 +101,7 @@ public class WhiteController extends CoreBaseController {
@Autowired
private SysUserPasswordUtil userPasswordUtil;
@Resource(name=CommonConstWords.IMPP_REDIS_RES)
@Resource(name = CommonConstWords.IMPP_REDIS_RES)
private ImppRedis redisRes;
@Autowired
@ -398,15 +407,50 @@ public class WhiteController extends CoreBaseController {
@GetMapping(value = "/sys-order-no-rule/get-order-no/{code}")
@ApiOperation(value = "根据单号规则代码,生成单号")
public ResultBean getOrderNo(@PathVariable("code") String code) {
Lock lock = redisCore.getFairLock(REDIS_PREFIX_LOCK_GET_ORDER_NO);
try {
ValidatorBean.checkNotNull(code, "code不能为空");
// 获取锁
lock.lock();
SysOrderNoRule sysOrderNoRule = synchronizedService.nextOrderNo(code);
return ResultBean.success("操作成功").setResultObject(sysOrderNoRule).setCode(ResourceEnumUtil.MESSAGE.SUCCESS.getCode());
} catch (ImppBusiException busExcep) {
return ResultBean.fail(busExcep);
} catch (Exception e) {
return ImppExceptionBuilder.newInstance().buildExceptionResult(e);
} finally {
lock.unlock();
}
}
/**
*
*
* @param code
* @param num
* @return
*/
@GetMapping(value = "/sys-order-no-rule/get-order-no/{code}/{num}")
@ApiOperation(value = "根据单号规则代码,生成单号")
public ResultBean<String> getOrderNo(@PathVariable("code") String code, @PathVariable("num") Integer num) {
Lock lock = redisCore.getFairLock(REDIS_PREFIX_LOCK_BATCH_GET_ORDER_NO);
try {
ValidatorBean.checkNotNull(code, "code不能为空");
ValidatorBean.checkNotZero(num, "次数不能为零");
// 获取锁
lock.tryLock(15, TimeUnit.SECONDS);
List<String> orderNoList = synchronizedService.nextOrderNo(code, num).stream().map(SysOrderNoRule::getOrderNo).collect(Collectors.toList());
return ResultBean.success("操作成功").setResultList(orderNoList).setCode(ResourceEnumUtil.MESSAGE.SUCCESS.getCode());
} catch (ImppBusiException busExcep) {
return ResultBean.fail(busExcep);
} catch (Exception e) {
return ImppExceptionBuilder.newInstance().buildExceptionResult(e);
} finally {
lock.unlock();
}
}
@ -435,6 +479,7 @@ public class WhiteController extends CoreBaseController {
/**
*
*
* @return
*/
private CommonEnumUtil.LOG_LOGIN_PLATFORM getLoginPlatform(){
@ -514,6 +559,7 @@ public class WhiteController extends CoreBaseController {
/**
*
*
* @param model
* @return
*/
@ -554,6 +600,7 @@ public class WhiteController extends CoreBaseController {
/**
*
*
* @return
*/
@AnnoIgnoreLog

@ -12,6 +12,7 @@ import cn.estsh.i3plus.platform.common.tool.StringTool;
import cn.estsh.i3plus.platform.common.tool.ZipTool;
import cn.estsh.i3plus.platform.common.util.CommonConstWords;
import cn.estsh.i3plus.platform.common.util.PlatformConstWords;
import cn.estsh.i3plus.pojo.base.bean.ImppFile;
import cn.estsh.i3plus.pojo.base.bean.ListPager;
import cn.estsh.i3plus.pojo.base.common.Pager;
import cn.estsh.i3plus.pojo.base.enumutil.CommonEnumUtil;
@ -22,7 +23,6 @@ import cn.estsh.impp.framework.base.controller.CoreBaseController;
import cn.estsh.impp.framework.boot.exception.ImppBusiException;
import cn.estsh.impp.framework.boot.exception.ImppExceptionBuilder;
import cn.estsh.impp.framework.boot.fileservice.ImppFileService;
import cn.estsh.i3plus.pojo.base.bean.ImppFile;
import cn.estsh.impp.framework.boot.util.ImppRedis;
import cn.estsh.impp.framework.boot.util.ResultBean;
import cn.estsh.impp.framework.boot.util.ValidatorBean;
@ -38,6 +38,11 @@ import java.io.File;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.stream.Collectors;
import static cn.estsh.i3plus.platform.common.util.CommonConstWords.REDIS_PREFIX_LOCK_GET_ORDER_NO;
/**
* @Description :
@ -388,15 +393,21 @@ public class SysOrderNoRuleController extends CoreBaseController {
@GetMapping(value = "/get-order-no/{code}")
@ApiOperation(value = "根据单号规则代码,生成单号")
public ResultBean<SysOrderNoRule> getOrderNo(@PathVariable("code") String code) {
Lock lock = redisCore.getLock(REDIS_PREFIX_LOCK_GET_ORDER_NO);
try {
ValidatorBean.checkNotNull(code, "code不能为空");
// 获取锁
lock.tryLock(10, TimeUnit.SECONDS);
SysOrderNoRule sysOrderNoRule = synchronizedService.nextOrderNo(code);
return ResultBean.success("操作成功").setResultObject(sysOrderNoRule).setCode(ResourceEnumUtil.MESSAGE.SUCCESS.getCode());
} catch (ImppBusiException busExcep) {
return ResultBean.fail(busExcep);
} catch (Exception e) {
return ImppExceptionBuilder.newInstance().buildExceptionResult(e);
} finally {
lock.unlock();
}
}
@ -409,19 +420,22 @@ public class SysOrderNoRuleController extends CoreBaseController {
@GetMapping(value = "/get-order-no/{code}/{num}")
@ApiOperation(value = "根据单号规则代码,生成单号")
public ResultBean<String> getOrderNo(@PathVariable("code") String code,@PathVariable("num") Integer num) {
Lock lock = redisCore.getLock(REDIS_PREFIX_LOCK_GET_ORDER_NO);
try {
ValidatorBean.checkNotNull(code, "code不能为空");
ValidatorBean.checkNotZero(num,"次数不能为零");
List<String> orderNoList = new ArrayList<>();
for (int i = 0; i < num; i++) {
orderNoList.add(synchronizedService.nextOrderNo(code).getOrderNo());
}
// 获取锁
lock.tryLock(10, TimeUnit.SECONDS);
List<String> orderNoList = synchronizedService.nextOrderNo(code,num).stream().map(SysOrderNoRule::getOrderNo).collect(Collectors.toList());
return ResultBean.success("操作成功").setResultList(orderNoList).setCode(ResourceEnumUtil.MESSAGE.SUCCESS.getCode());
} catch (ImppBusiException busExcep) {
return ResultBean.fail(busExcep);
} catch (Exception e) {
return ImppExceptionBuilder.newInstance().buildExceptionResult(e);
} finally {
lock.unlock();
}
}
}

@ -6,6 +6,8 @@ import cn.estsh.i3plus.pojo.platform.bean.SysOrderNoRule;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* @Description :
* @Reference :
@ -23,4 +25,16 @@ public class SynchronizedService implements ISynchronizedService {
public synchronized SysOrderNoRule nextOrderNo(String code) {
return sysOrderNoRuleService.doGetSysOrderNoRuleCode(code);
}
/**
*
*
* @param code
* @param num
* @return
*/
@Override
public synchronized List<SysOrderNoRule> nextOrderNo(String code, int num) {
return sysOrderNoRuleService.doGetSysOrderNoRuleByCodeAndNum(code,num);
}
}

@ -1,7 +1,9 @@
package cn.estsh.i3plus.core.apiservice.serviceimpl.busi;
import cn.estsh.i3plus.core.api.iservice.busi.ISysOrderNoRuleService;
import cn.estsh.i3plus.core.apiservice.util.CloneTool;
import cn.estsh.i3plus.core.apiservice.util.OrderNoMakeUtil;
import cn.estsh.i3plus.platform.common.exception.ImppExceptionEnum;
import cn.estsh.i3plus.platform.common.tool.StringTool;
import cn.estsh.i3plus.pojo.base.bean.DdlPackBean;
import cn.estsh.i3plus.pojo.base.bean.ListPager;
@ -13,13 +15,13 @@ import cn.estsh.i3plus.pojo.platform.bean.SysOrderNoRule;
import cn.estsh.i3plus.pojo.platform.repository.SysOrderNoRuleRepository;
import cn.estsh.i3plus.pojo.platform.sqlpack.CoreHqlPack;
import cn.estsh.impp.framework.boot.exception.ImppExceptionBuilder;
import cn.estsh.i3plus.platform.common.exception.ImppExceptionEnum;
import io.swagger.annotations.ApiOperation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
/**
@ -114,6 +116,53 @@ public class SysOrderNoRuleService implements ISysOrderNoRuleService {
}
}
/**
*
*
* @param code
* @param num
* @return
*/
@Override
public synchronized List<SysOrderNoRule> doGetSysOrderNoRuleByCodeAndNum(String code, int num) {
SysOrderNoRule sysOrderNoRule = sysOrderNoRuleRDao.getByProperty("orderNoRuleCode", code);
sysOrderNoRuleRDao.detachObject(sysOrderNoRule);
List<SysOrderNoRule> resultList = new ArrayList<>();
if (sysOrderNoRule == null) {
throw ImppExceptionBuilder.newInstance()
.setSystemID(CommonEnumUtil.SOFT_TYPE.CORE.getCode())
.setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION_DATA_NOT_EXIT.getCode())
.setErrorDetail("[" + code + "]规则代码不存在存在")
.setErrorSolution("请重新输入规则代码")
.build();
} else if (sysOrderNoRule.getOrderNoRuleStatus() == CommonEnumUtil.TRUE_OR_FALSE.FALSE.getValue()) {
throw ImppExceptionBuilder.newInstance()
.setSystemID(CommonEnumUtil.SOFT_TYPE.CORE.getCode())
.setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
.setErrorDetail("[" + code + "]单号规则已禁用")
.setErrorSolution("请重新输入规则代码")
.build();
} else {
try {
for (int i = 0; i < num; i++) {
sysOrderNoRule = OrderNoMakeUtil.next((SysOrderNoRule) CloneTool.clone(sysOrderNoRule));
resultList.add(sysOrderNoRule);
}
}catch (Exception e){
LOGGER.error("单号生成异常:",e);
throw ImppExceptionBuilder.newInstance()
.setSystemID(CommonEnumUtil.SOFT_TYPE.CORE.getCode())
.setErrorCode(ImppExceptionEnum.BUSINESS_EXCEPTION.getCode())
.setErrorDetail("单号生成异常 %s",e.getMessage())
.build();
}
sysOrderNoRuleRDao.update(sysOrderNoRule);
return resultList;
}
}
@Override
public void updateSysOrderNoRuleCodeStatusById(Long id, Integer status) {
sysOrderNoRuleRDao.updateByProperties("id", id, "orderNoRuleStatus", status);

@ -0,0 +1,231 @@
package cn.estsh.i3plus.core.apiservice.util;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.*;
/**
* @Description :
* @Reference :
* @Author : yunhao
* @CreateDate : 2020-08-12 13:44
* @Modify:
**/
public class CloneTool {
public static final Logger LOGGER = LoggerFactory.getLogger(CloneTool.class);
/**
*
*/
static Class[] needlessCloneClasses = new Class[]{String.class,Boolean.class,Character.class,Byte.class,Short.class,
Integer.class,Long.class,Float.class,Double.class,Void.class,Object.class,Class.class
};
/**
*
* @param c
* @return
*/
private static boolean isNeedlessClone(Class c){
if(c.isPrimitive()){//基本类型
return true;
}
for(Class tmp:needlessCloneClasses){//是否在无需复制类型数组里
if(c.equals(tmp)){
return true;
}
}
return false;
}
/**
*
* @param value
* @return
* @throws IllegalAccessException
*/
private static Object createObject(Object value) throws IllegalAccessException{
try {
return value.getClass().newInstance();
} catch (InstantiationException e) {
return null;
} catch (IllegalAccessException e) {
throw e;
}
}
/**
*
* @param value
* @param level 0Object
* 00
* @return
* @throws IllegalAccessException
* @throws InstantiationException
*/
public static Object clone(Object value,int level) throws IllegalAccessException, InstantiationException {
if(value==null){
return null;
}
if(level==0){
return value;
}
Class c = value.getClass();
if(isNeedlessClone(c)){
return value;
}
level--;
if(value instanceof Collection){//复制新的集合
Collection tmp = (Collection)c.newInstance();
for(Object v:(Collection)value){
tmp.add(clone(v,level));//深度复制
}
value = tmp;
}
else if(c.isArray()){//复制新的Array
//首先判断是否为基本数据类型
if(c.equals(int[].class)){
int[] old = (int[])value;
value = (int[]) Arrays.copyOf(old, old.length);
}
else if(c.equals(short[].class)){
short[] old = (short[])value;
value = (short[])Arrays.copyOf(old, old.length);
}
else if(c.equals(char[].class)){
char[] old = (char[])value;
value = (char[])Arrays.copyOf(old, old.length);
}
else if(c.equals(float[].class)){
float[] old = (float[])value;
value = (float[])Arrays.copyOf(old, old.length);
}
else if(c.equals(double[].class)){
double[] old = (double[])value;
value = (double[])Arrays.copyOf(old, old.length);
}
else if(c.equals(long[].class)){
long[] old = (long[])value;
value = (long[])Arrays.copyOf(old, old.length);
}
else if(c.equals(boolean[].class)){
boolean[] old = (boolean[])value;
value = (boolean[])Arrays.copyOf(old, old.length);
}
else if(c.equals(byte[].class)){
byte[] old = (byte[])value;
value = (byte[])Arrays.copyOf(old, old.length);
}
else {
Object[] old = (Object[])value;
Object[] tmp = (Object[])Arrays.copyOf(old, old.length, old.getClass());
for(int i = 0;i<old.length;i++){
tmp[i] = clone(old[i],level);
}
value = tmp;
}
}
else if(value instanceof Map){//复制新的MAP
Map tmp = (Map)c.newInstance();
Map org = (Map)value;
for(Object key:org.keySet()){
tmp.put(key, clone(org.get(key),level));//深度复制
}
value = tmp;
}
else {
Object tmp = createObject(value);
if(tmp==null){//无法创建新实例则返回对象本身,没有克隆
return value;
}
Set<Field> fields = new HashSet<Field>();
while(c!=null&&!c.equals(Object.class)){
fields.addAll(Arrays.asList(c.getDeclaredFields()));
c = c.getSuperclass();
}
for(Field field:fields){
if(!Modifier.isFinal(field.getModifiers())){//仅复制非final字段
field.setAccessible(true);
field.set(tmp, clone(field.get(value),level));//深度复制
}
}
value = tmp;
}
return value;
}
/**
*
* @param value
* @return
* @throws IllegalAccessException
* @throws InstantiationException
*/
public static Object clone(Object value) throws IllegalAccessException, InstantiationException {
return clone(value,1);
}
/**
*
* @param value
* @return
* @throws IllegalAccessException
* @throws InstantiationException
*/
public static Object deepClone(Object value) throws IllegalAccessException, InstantiationException {
return clone(value,-1);
}
//数据100 深度10 测试
//======普通赋值======
//数据100 深度10
//普通赋值耗时:4~8
//======克隆工具1======
//数据100 深度10
//克隆工具1耗时:1272~1987
//======克隆工具2-1======
//数据100 深度10
//克隆工具2-1耗时:5~7
//======克隆工具2-2======
//数据100 深度10
//克隆工具2-2耗时:15~19
//
//数据100 深度20 测试
//======普通赋值======
//数据100 深度20
//普通赋值耗时:6
//======克隆工具1======
//数据100 深度20
//克隆工具1耗时:1772
//======克隆工具2-1======
//数据100 深度20
//克隆工具2-1耗时:71
//======克隆工具2-2======
//数据100 深度20
//克隆工具2-2耗时:216
// 性能低
// public static <T> T clone(Object cloneObj) {
// ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
// ObjectOutputStream out;
// try {
// out = new ObjectOutputStream(byteOut);
// out.writeObject(cloneObj);
//
// ByteArrayInputStream byteIn = new ByteArrayInputStream(byteOut.toByteArray());
//
// ObjectInputStream in = new ObjectInputStream(byteIn);
//
// T retObj = (T) in.readObject();
//
// return retObj;
// } catch (IOException | ClassNotFoundException e) {
// LOGGER.error("对象" + cloneObj.getClass().getName() + "克隆异常:", e);
// }
// return null;
// }
}
Loading…
Cancel
Save