diff --git a/modules/i3plus-core-apiservice/src/main/java/cn/estsh/i3plus/core/apiservice/serviceimpl/base/SynchronizedService.java b/modules/i3plus-core-apiservice/src/main/java/cn/estsh/i3plus/core/apiservice/serviceimpl/base/SynchronizedService.java index 21b9d22..87fd5d2 100644 --- a/modules/i3plus-core-apiservice/src/main/java/cn/estsh/i3plus/core/apiservice/serviceimpl/base/SynchronizedService.java +++ b/modules/i3plus-core-apiservice/src/main/java/cn/estsh/i3plus/core/apiservice/serviceimpl/base/SynchronizedService.java @@ -12,6 +12,7 @@ import cn.estsh.impp.framework.boot.exception.ImppExceptionBuilder; import cn.estsh.impp.framework.boot.util.ImppRedis; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.math.NumberUtils; +import org.redisson.api.RLock; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.amqp.rabbit.core.RabbitTemplate; @@ -67,43 +68,47 @@ public class SynchronizedService implements ISynchronizedService { @Override public synchronized List nextOrderNo(String code, int num) { //先拿规则 - SysOrderNoRule codeRole = sysOrderNoRuleService.getSysOrderNoRuleByCode(code); - if (codeRole == null) { - throw ImppExceptionBuilder.newInstance() - .setSystemID(CommonEnumUtil.SOFT_TYPE.CORE.getCode()) - .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION_DATA_NOT_EXIT.getCode()) - .setErrorDetail("[" + code + "]规则代码不存在存在") - .setErrorSolution("请重新输入规则代码") - .build(); - } else if (codeRole.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(); - } - - sysOrderNoRuleService.detachSysOrderNoRule(codeRole); - - String orderNoTemplate = OrderNoMakeUtil.getOrderNoTemplate(codeRole); - String redisKey = REDIS_PREFIX_LOCK_GET_ORDER_NO + ":" + code + ":" + orderNoTemplate; - - long orginSerialNo = codeRole.getSerialNo(); - if (codeRole.getSerialNo() < 0 || OrderNoMakeUtil.isCycleByPrefix(codeRole, orderNoTemplate)) { - orginSerialNo = 0; - } - long incr = codeRole.getSerialNoIncrement() * num; - - //缓存增加 - //先判断redis是否存在,如果不存在,则用默认初始值+步长*数量,如果存在,则添加步长 * 数量 - codeRole.setSerialNo(redisRes.putObjAdditional(redisKey, orginSerialNo, incr) - incr); - - // 设置缓存有效期 - redisRes.expire(redisKey, PlatformConstWords.REDIS_EXPIRE_SECONDS); - - // 生成单号更缓存 - List orderNoRuleList = sysOrderNoRuleService.doGetSysOrderNoRuleByNum(codeRole, orderNoTemplate, num); + String lockKey = CommonConstWords.REDIS_PREFIX_LOCK_GET_ORDER_NO + ":" + "LOCK" + ":" + code; + RLock rLock = (RLock) redisRes.getLock(lockKey); + rLock.lock(); + try { + SysOrderNoRule codeRole = sysOrderNoRuleService.getSysOrderNoRuleByCode(code); + if (codeRole == null) { + throw ImppExceptionBuilder.newInstance() + .setSystemID(CommonEnumUtil.SOFT_TYPE.CORE.getCode()) + .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION_DATA_NOT_EXIT.getCode()) + .setErrorDetail("[" + code + "]规则代码不存在存在") + .setErrorSolution("请重新输入规则代码") + .build(); + } else if (codeRole.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(); + } + + sysOrderNoRuleService.detachSysOrderNoRule(codeRole); + + String orderNoTemplate = OrderNoMakeUtil.getOrderNoTemplate(codeRole); + String redisKey = REDIS_PREFIX_LOCK_GET_ORDER_NO + ":" + code + ":" + orderNoTemplate; + + long orginSerialNo = codeRole.getSerialNo(); + if (codeRole.getSerialNo() < 0 || OrderNoMakeUtil.isCycleByPrefix(codeRole, orderNoTemplate)) { + orginSerialNo = 0; + } + long incr = codeRole.getSerialNoIncrement() * num; + + //缓存增加 + //先判断redis是否存在,如果不存在,则用默认初始值+步长*数量,如果存在,则添加步长 * 数量 + codeRole.setSerialNo(redisRes.putObjAdditional(redisKey, orginSerialNo, incr) - incr); + + // 设置缓存有效期 + redisRes.expire(redisKey, PlatformConstWords.REDIS_EXPIRE_SECONDS); + + // 生成单号更缓存 + List orderNoRuleList = sysOrderNoRuleService.doGetSysOrderNoRuleByNum(codeRole, orderNoTemplate, num); // FIXME 松下推送量太大并且该记录无意义 先注释 // try { @@ -112,8 +117,15 @@ public class SynchronizedService implements ISynchronizedService { // LOGGER.error("单号记录推送异常", e); // } - // 生成单号更缓存 - return orderNoRuleList; + // 生成单号更缓存 + return orderNoRuleList; + } catch (Exception e) { + LOGGER.error("生成单号失败,单号代码:{},num:{}", code, num, e); + } finally { + if (rLock.isHeldByCurrentThread()) { + rLock.unlock(); + } + } + return null; } - } diff --git a/modules/i3plus-core-apiservice/src/test/java/test/cn/estsh/i3plus/core/apiservice/serviceimpl/busi/TestSynchronizedService.java b/modules/i3plus-core-apiservice/src/test/java/test/cn/estsh/i3plus/core/apiservice/serviceimpl/busi/TestSynchronizedService.java new file mode 100644 index 0000000..2b7a578 --- /dev/null +++ b/modules/i3plus-core-apiservice/src/test/java/test/cn/estsh/i3plus/core/apiservice/serviceimpl/busi/TestSynchronizedService.java @@ -0,0 +1,67 @@ +package test.cn.estsh.i3plus.core.apiservice.serviceimpl.busi; + +import cn.estsh.i3plus.core.api.iservice.base.ISynchronizedService; +import cn.estsh.i3plus.core.apiservice.serviceimpl.base.SynchronizedService; +import cn.estsh.i3plus.platform.common.util.CommonConstWords; +import cn.estsh.i3plus.pojo.platform.bean.SysOrderNoRule; +import cn.estsh.impp.framework.boot.util.ImppRedis; +import cn.estsh.impp.framework.run.ImppGo; + +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.context.testng.AbstractTestNGSpringContextTests; +import org.springframework.util.ObjectUtils; +import org.testng.TestRunner; +import org.testng.annotations.Test; + +import javax.annotation.Resource; +import java.util.Random; + +/** + * @author ns + * 测试生成orderNo是否重复 + * @create 2021/9/15 0015 下午 13:46 + */ +@RunWith(SpringRunner.class) +@SpringBootTest(classes = ImppGo.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) +public class TestSynchronizedService extends AbstractTestNGSpringContextTests { + + @Autowired + private ISynchronizedService synchronizedService; + + @Resource(name = CommonConstWords.IMPP_REDIS_RES) + private ImppRedis resRedis; + + public static String orderNoKey = CommonConstWords.REDIS_PREFIX_LOCK_GET_ORDER_NO + ":" + "LOCK" + ":" + "PO_ORDER_NO" + ":" + "ORDERNO"; + public static String serialNoKey = CommonConstWords.REDIS_PREFIX_LOCK_GET_ORDER_NO + ":" + "LOCK" + ":" + "PO_ORDER_NO" + ":" + "SERIALNO"; + + + @Test(threadPoolSize = 5) + public void getOrderNo() { + while (true) { + try { + SysOrderNoRule sysOrderNoRule = synchronizedService.nextOrderNo("PO_ORDER_NO"); + System.out.println(sysOrderNoRule); + System.out.println(sysOrderNoRule.getOrderNo()); + System.out.println(sysOrderNoRule.getSerialNo()); + if (!ObjectUtils.isEmpty(resRedis.getHash(orderNoKey + ":ORDERNO" ,sysOrderNoRule.getOrderNo()))){ + throw new Exception("订单号重复"); + }else{ + resRedis.putHash(orderNoKey + ":ORDERNO",sysOrderNoRule.getOrderNo(), System.currentTimeMillis()); + } + if (!ObjectUtils.isEmpty(resRedis.getHash(orderNoKey + ":SERIALNO", String.valueOf(sysOrderNoRule.getSerialNo())))){ + throw new Exception("订单号重复"); + }else { + resRedis.putHash(orderNoKey + ":SERIALNO", String.valueOf(sysOrderNoRule.getSerialNo()), System.currentTimeMillis()); + } + Thread.sleep(new Random().nextInt(20)); + } catch (InterruptedException e) { + e.printStackTrace(); + } catch (Exception e) { + e.printStackTrace(); + } + } + } +}