收藏
回答

服务器卡顿了15秒,导致同一笔微信支付的两次通知都被处理了,导致充值两次,请大神指点解决方案?

如下方代码所示:

@RequestMapping(value = "/notifysign")

public void notifyUrlSign是接收微信支付通知的controller。

@Transactional

public boolean notifyUrlSign是具体处理接收通知后续业务的函数

两个方法的具体代码在最下方,我先描述问题:

问题在方法public boolean notifyUrlSign中,(pltfWebpayflow.getPaysStatus().equals((short) 0))是关键标识,只有在pltfWebpayflow表的PaysStatus字段值是0时,才处理这笔支付的后续业务表。并且在if (pltfWebpayflow.getPaysStatus().equals((short) 0))判断通过之后,首先就pltfWebpayflow.setPaysStatus((short) 1);并且pltfWebpayflowJPA.saveAndFlush(pltfWebpayflow);保存了这个表,就是为了防止同一笔微信支付被重复处理。

现在的问题是,一笔微信支付的第一次通知发给我的服务器,由于访问量大等原因程序卡顿了一段时间应该有15秒,应该是卡在了if (pltfWebpayflow.getPaysStatus().equals((short) 0))的判断成功之后,然后服务器又接收到该笔支付的第二次通知,此时可能程序卡顿恢复了。

因为上一次通知还没有处理完,pltfWebpayflow表的PaysStatus字段值此时还是0,导致第二次通知又被处理了,也就是该笔支付的两次微信通知都在同时处理,也就是同一笔微信支付被处理了两次,zhxx.setYe(zhxx.getYe().add(fee));业务流水被加了两次。

服务器硬件确实不太好,偶尔会出现这种现象,我也没有升级硬件的权利,请大神从程序上给个修改解决建议,谢谢。

详细代码如下:

	@RequestMapping(value = "/notifysign")
	public void notifyUrlSign(HttpServletRequest request, HttpServletResponse response) throws Exception {
		String re = "<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[ERROR]]></return_msg></xml>";
		Map<String, String> map = WxWebXml.parseXml(request, logger);
		logger.debug("notimsg: " + JSON.toJSONString(map));
		if (map.get("return_code").equals("SUCCESS")) {
			if (map.get("result_code").equals("SUCCESS")) {
				if (wxWebService.notifyUrlSign(map, request, response)) {
					re = "<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>";
				}
			}
		}
		// response.getOutputStream().println(re);
		PrintWriter out = response.getWriter();
		out.print(re);
		out.flush();
		out.close();
		// return re;
	}
	@Transactional
	public boolean notifyUrlSign(Map<String, String> map, HttpServletRequest request, HttpServletResponse response) {
		String ottrid = map.get("out_trade_no");
		BigDecimal fee = new BigDecimal(map.get("total_fee"));
		logger.debug("notifysgstart");
		PltfWebpayflow pltfWebpayflow = pltfWebpayflowJPA.findOne(ottrid);
		SortedMap<String, Object> sortedMap = new TreeMap<>(map);
		String sgin = WxPayTool.createWxPaySign(WxConstants.KEY, sortedMap, logger);
		logger.info("notifysign: " + sgin + " , " + JSONObject.toJSONString(pltfWebpayflow));
		if (pltfWebpayflow != null && pltfWebpayflow.getTotalAmount().compareTo(fee) == 0
				&& sgin.equals(map.get("sign"))) {
			if (pltfWebpayflow.getPaysStatus().equals((short) 0)) {


				logger.info("notifystart567");
				DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyyMMddHHmmss");
				LocalDateTime ldt = LocalDateTime.parse(map.get("time_end"), dtf);
				Date date = Date.from(ldt.atZone(ZoneId.systemDefault()).toInstant());
				QZhxxCk qZhxxCk = QZhxxCk.zhxxCk;
				logger.debug("notifystart123");
				Integer lshmax = queryFactory.select(qZhxxCk.lsh.max()).from(qZhxxCk).fetchFirst();
				if (lshmax == null) {
					lshmax = 0;
				}
				logger.info("notifystart2: " + lshmax);


				ZhxxCk zhxxCk = new ZhxxCk();
				zhxxCk.setYpaysStatus(pltfWebpayflow.getPaysStatus());
				
				pltfWebpayflow.setFeeType(map.get("fee_type"));
				pltfWebpayflow.setReturnMsg(map.get("return_msg"));
				pltfWebpayflow.setGmtPayment(date);
				pltfWebpayflow.setIsnotify((short) 1);
				pltfWebpayflow.setPaysStatus((short) 1);
				pltfWebpayflow.setResultCode(map.get("result_code"));
				pltfWebpayflow.setReturnCode(map.get("return_code"));
				pltfWebpayflow.setTradeNo(map.get("transaction_id"));


				if (map.get("is_subscribe") != null) {
					pltfWebpayflow.setIssubscribe((map.get("is_subscribe")));
				}
				pltfWebpayflowJPA.saveAndFlush(pltfWebpayflow);


				logger.info("notifyplwf CK: " + JSONObject.toJSONString(pltfWebpayflow));


				Zhxx zhxx = zhxxJPA.findOne(pltfWebpayflow.getForeignkey());
				logger.info("notifyzhxx 1 CK: " + JSONObject.toJSONString(zhxx));
				
				if (zhxx.getYe() == null) {
					zhxx.setYe(new BigDecimal("0"));
				}
				fee = fee.divide(new BigDecimal(100), 2, BigDecimal.ROUND_HALF_UP);
				
				zhxxCk.setYye(zhxx.getYe());
				
				zhxx.setYe(zhxx.getYe().add(fee));
				zhxxJPA.saveAndFlush(zhxx);
				logger.info("notifyzhxx 2 CK: " + JSONObject.toJSONString(zhxx));
				
				// Date now = new Date();
				zhxxCk.setId(UUID.randomUUID().toString().toUpperCase().replaceAll("-", ""));
				zhxxCk.setZh(zhxx.getZh());
				zhxxCk.setCkrq(date);
				zhxxCk.setBenh(zhxx.getBenh());
				zhxxCk.setYysh(zhxx.getBenh().substring(0, 2));
				zhxxCk.setKh(zhxx.getKh());
				zhxxCk.setXm(zhxx.getXm());
				zhxxCk.setDz(zhxx.getDz());
				zhxxCk.setCkje(fee);
				zhxxCk.setYe(zhxx.getYe());
				zhxxCk.setJsry("888888");
				zhxxCk.setOpName("微信支付");
				DateFormat dateFormat = new SimpleDateFormat("yyyyMMdd");
				String str = dateFormat.format(date);
				zhxxCk.setRq(str);
				zhxxCk.setLsh(lshmax + 1);


				zhxxCk.setGmtPayment(pltfWebpayflow.getGmtPayment());
				zhxxCk.setIsnotify(pltfWebpayflow.getIsnotify());
				zhxxCk.setOutTradeNo(pltfWebpayflow.getOutTradeNo());
				zhxxCk.setTradeNo(pltfWebpayflow.getTradeNo());
				zhxxCk.setPaysStatus(pltfWebpayflow.getPaysStatus());
				
				zhxxCkJPA.saveAndFlush(zhxxCk);
				logger.info("notify CK: " + JSONObject.toJSONString(zhxxCk));


				ZhxxWxwebRec3 zhxxWxwebRec3;
				QZhxxWxwebRec3 qZhxxWxwebRec3 = QZhxxWxwebRec3.zhxxWxwebRec3;
				List<ZhxxWxwebRec3> bczxxWxwebRec3s = (List<ZhxxWxwebRec3>) zhxxWxwebRec3JPA.findAll(qZhxxWxwebRec3.openid
						.eq(pltfWebpayflow.getOpenid()).and(qZhxxWxwebRec3.zh.eq(zhxx.getZh())));
				if (bczxxWxwebRec3s.size() > 0) {
					zhxxWxwebRec3 = bczxxWxwebRec3s.get(0);
				} else {
					zhxxWxwebRec3 = new ZhxxWxwebRec3();
				}
				zhxxWxwebRec3.setOpenid(pltfWebpayflow.getOpenid());
				zhxxWxwebRec3.setZh(zhxx.getZh());
				zhxxWxwebRec3.setId(zhxxCk.getId());
				zhxxWxwebRec3JPA.saveAndFlush(zhxxWxwebRec3);
				logger.info("notifyRec CK: " + JSONObject.toJSONString(zhxxWxwebRec3));


				// int i=1/0;
			} else {
				logger.info("notifystartOver");
			}
			
			return true;
		}
		return false;
	}


回答关注问题邀请回答
收藏

1 个回答

  • 江南
    江南
    2023-11-29

    根据订单号加个锁不行嘛

    2023-11-29
    有用 1
    回复 2
    • 2023-11-30
      最简单的就是多建一张表,用来存已经处理的订单Id,给这个Id建唯一索引。
      然后把在写入这个表的订单id的同一个事务去修改账户充值。
      然后第一条可以正常充值,第二笔就充值失败了
      2023-11-30
      回复
    • 江南
      江南
      2023-11-30回复
      不是加个锁最简单吗???
      2023-11-30
      回复
登录 后发表内容