通过js fetch() 模拟后台接口的并发测试

业务需求:今天开发人员向我反馈,说之前的旧系统存在,在高并发的情况下,会产生流水发号重新的现象。

说是迟,写是快。快速写完高并发情况下的流水号生成服务。核心代码如下:

@Controller
@RequestMapping("/api/sys/pip/record")
@Api(value = "流水号记录Controlle", tags = "流水号记录操作服务")
public class SysPipNumberRecordController extends AbstractController {
	
	@Autowired
	private SysPipNumberRecordService service;
	
	@ApiOperation(httpMethod = "POST", value = "流水号记录信息保存")
	@RequestMapping(value = "/insert", method = { RequestMethod.POST }, produces = "application/json;charset=UTF-8")
	@ResponseBody
	public Result insert(
			@RequestBody @ApiParam(name = "流水号规则对象", value = "json格式对象", required = true) SysPipNumberRecord entity) {
		
		// 判断流水规则是否为空
		if(!StringUtils.isEmpty(entity.getRuleSid())){
			service.insertSelective(entity);
			return Result.ok();
		} else {
			return Result.error("流水规则不存在");
		}

	}
@Override
	public int insertSelective(SysPipNumberRecord record) {
		// TODO Auto-generated method stub
		// 解决并发请求,发号重复问题:锁定当前代码块
		synchronized(this){
			// 分布式sid 生成
			SnowflakeIdGenerator snowflake = new SnowflakeIdGenerator(0,2);
			record.setSid(Long.toBinaryString(snowflake.nextId()));
			
			// 判断流水规则 是否在流水记录中生成
			Map<String, Object> parame = new HashMap<String, Object>();
			parame.put("ruleSid", record.getRuleSid());
			
			// 公共属性
			SysPipNumberRule rule = ruleMapper.selectByPrimaryKey(record.getRuleSid());
			record.setCategory(rule.getCategory());
			record.setZoneOrgCode(rule.getZoneOrgCode());
			
			List<SysPipNumberRecord> list = mapper.selectAll(parame);
			if (list != null && list.size() > 0) {
				// 获取流水记录最大值
				List<Integer> num = list.stream().map(SysPipNumberRecord::getInitValue).collect(Collectors.toList());
				Integer number = Collections.max(num) + 1;
				
				record.setInitValue(number);
				// 序列号
				String serialNumber = StringFormatUtil.addZeroForNum(String.valueOf(number),
						rule.getLength());
				
				StringBuilder builder = new StringBuilder();
				// 判断是否启动分类
				if(rule.getIsCategory().equalsIgnoreCase("1")){
					// 判断是否截取分类
					if(rule.getCutLength() != null && rule.getCutLength() > 0){
						// 判断截取长度与分类key 长度问题
						if(rule.getCategory().length() >= rule.getCutLength()){
							builder.append(rule.getCategory().substring(0, rule.getCutLength()));							
						} else {
							builder.append(rule.getCategory());
						}
					} else {
						builder.append(rule.getCategory());
					}
					// 判断连接符是否配置
					if(!StringUtils.isEmpty(rule.getConnector())){
						builder.append(rule.getConnector());
					}
				} 
				// 判断是否启动日期
				if (rule.getIsDate().equalsIgnoreCase("1")) {
					SimpleDateFormat format = new SimpleDateFormat(rule.getDateFormat());
					builder.append(format.format(new Date()));
					if(!StringUtils.isEmpty(rule.getConnector())){
						builder.append(rule.getConnector());
					}
				}
				// 添加流水号
				builder.append(serialNumber);
				record.setPipNumberValue(builder.toString());
				
			} else {
				record.setInitValue(rule.getStartValue());
				// 序列号
				String serialNumber = StringFormatUtil.addZeroForNum(String.valueOf(rule.getStartValue()),
						rule.getLength());
				StringBuilder builder = new StringBuilder();
				// 判断是否启动分类
				if(rule.getIsCategory().equalsIgnoreCase("1")){
					// 判读是否截取分类
					if(rule.getCutLength() != null && rule.getCutLength() > 0){
						// 判断截取长度与分类key 长度问题
						if(rule.getCategory().length() >= rule.getCutLength()){
							builder.append(rule.getCategory().substring(0, rule.getCutLength()));							
						} else {
							builder.append(rule.getCategory());
						}
					} else {
						builder.append(rule.getCategory());
					}
					
					
					if(!StringUtils.isEmpty(rule.getConnector())){
						builder.append(rule.getConnector());
					}
				} 
				// 判断是否启动日期
				if (rule.getIsDate().equalsIgnoreCase("1")) {
					SimpleDateFormat format = new SimpleDateFormat(rule.getDateFormat());
					builder.append(format.format(new Date()));
					if(!StringUtils.isEmpty(rule.getConnector())){
						builder.append(rule.getConnector());
					}
				}
				// 添加流水号
				builder.append(serialNumber);
				record.setPipNumberValue(builder.toString());
			}
			
			// 数据入库
			return mapper.insertSelective(record);
		}
	}

核心代码已经写完,如何验证我写的代码,让我很纠结,测试人员提示我,可以使用ab 测试工具 模拟高并发的情况,但是我从我们公司的前端学到一手,通过HTML5 新特性fetch 函数模拟高并发.

前端js 代码如下:

var sends = (num) => {
	for(var i =0;i<num;i++) {
		fetch("http://localhost:9090/api/sys/pip/record/insert", {"credentials":"include","headers":{"accept":"application/json;charset=UTF-8","accept-language":"zh,en;q=0.9,zh-CN;q=0.8","content-type":"application/json"},"referrer":"http://localhost:9090/swagger-ui.html","referrerPolicy":"no-referrer-when-downgrade","body":"{\"ruleSid\":\"100011000100111000100000010101101000100001000000000000001010\"}","method":"POST","mode":"cors"})
	}
}

通过模拟2次,每次都是100 个请求,查看数据库结果,没有重复。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值