对接第三方支付接口-类似文件锁的编程小技巧

  在这次对接支付接口的时候,有如下场景:用户还款的时候,APP端只要请求了支付接口后,正常情况下,支付接口会同步返回结果状态,并且异步通知是否成功,支付状态以异步通知为准。这样的场景会出现一个问题,如果APP端请求了支付接口,异步通知迟迟未返回,这样一来,用户还款状态是无法更改(还款的逻辑处理实在异步通知里处理,因为一切以异步通知为准),并且对于用户来说他已经还款了,异步回调没来,可能支付成功,可能支付失败我们不知道,对于用户来说他已经支付还款了,按逻辑这一期还款他无需也不能做其他操作了,所以在回调通知来之前,这一期数据在APP端是需要做一个限制不能让用户操作,在这里加了一个“还款中”状态,标记请求支付接口之后,回调通知来之前的状态(正常情况下这段时间很短,短到让用户无法察觉)。

  加“还款中”的状态是可行的,后台服务端来更新还款记录的状态,由APP端请求,APP端在请求支付接口后支付接口同步返回成功后再请求后台的接口,更新还款记录的状态。这里有个问题:请求支付接口会有一个异步通知返回,我们在异步通知里进行相应的逻辑处理,包括更新还款记录的状态为“已还”,但是APP端同步请求成功后也会请求后台更新这条还款记录为“还款中”,操作同一条数据,我们一开始的做法是更新还款中的时候判断是否是“未还”状态,但是发现如果两个更新操作的方法“同时”处理,即异步通知还未更新为“已还”,更新为“还款中”的方法进去了,检索到这条记录仍是“未还”,同样会处理成“还款中”。这样一来有可能支付成功了,还款记录的状态还是“还款中”的情况,所以我们要解决并发的问题,人为控制如果回调通知已经来了,就没必要在请求后台改成“还款中”。

  这里用到的方法有点类似于“文件锁”,我们通过生成特定文件来标记是否异步通知成功(直接更新为“已还”),如果异步通知成功则不需要更新为“还款中”,如果先改成“还款中”,再改成“已还”也没有问题,如果两个方法同时进行,则根据生成的文件来标记一个方法是否提交完成,这里用到的是Spring的事务控制,另一个事务提交后再执行当前这个方法,主要做法为:在异步回调通知里的方法notifyUrl()开始的时候创建一个文件A,结束时删除这个文件;在更改成“还款中”的方法updateRpmting()开始时候也创建一个文件B,这里要判断A是否存在,如果A存在则当前线程延时60ms,等待notifyUrl()方法执行完毕,这时候还款记录的状态已经改成“已还”,不会再继续执行updateRpmting()方法改成“还款中”,当然在创建文件A的时候也会判断B是否存在,同样处理。这里生成文件的方法需要用java的synchronized来锁住,确保同一时间只有一次调用,生成一个文件。

RechargeUtil.java:(Globals.UNDER_LINE是定义的静态变量表示下划线 “_”)

  //创建一个唯一文件public static boolean creatOnlyFile(String rpmtIds,String myType, String otherType){// 创建一个files目录下面日期为子目录的rpmtId.txt文件String myFileName=files+"/" + DateUtils.date2Str(DateUtils.yyyyMMdd)+"/" + DigestUtils.md5Hex(rpmtIds) + Globals.UNDER_LINE + myType + ".txt";String otherFileName=files+"/" + DateUtils.date2Str(DateUtils.yyyyMMdd)+"/" + DigestUtils.md5Hex(rpmtIds) + Globals.UNDER_LINE + otherType + ".txt";System.out.println("文件地址为:" + myFileName);File myFile=new File(myFileName);if(!myFile.getParentFile().exists()){myFile.getParentFile().mkdirs();}File otherFile=new File(otherFileName);try {return createSynchronizedFile(myFile, otherFile);} catch (IOException e) {System.out.println("创建文件失败!");e.printStackTrace();}return false;}//同一时间创建一个唯一文件public synchronized static boolean createSynchronizedFile(File myFile, File otherFile) throws IOException {if(!otherFile.exists()){myFile.createNewFile();return true;}return false;}

  //删除存在的锁文件
  public static boolean deleteOnlyFile(String rpmtIds,String myType){

      File myFile=new File(files+"/" + DateUtils.date2Str(DateUtils.yyyyMMdd)+"/" + DigestUtils.md5Hex(rpmtIds) + Globals.UNDER_LINE + myType + ".txt");
      if(myFile.exists()){
        return myFile.delete();
      }
      return true;
   }

 

异步回调通知里调用创建文件的方法:

public void notifyUrl(PayRpmtEntity payRpmt, String noAgree ,JSONObject resultMap) throws Exception{//1.根据“还款-支付记录表”获取rpmtIds,循环修改还款计划状态String rpmtIds = payRpmt.getRpmtIds();//创建一个唯一文件int size = 0;while (size < 30 && !RechargeUtil.creatOnlyFile(rpmtIds,"01", "02")) {Thread.sleep(100);size++;}if (size >= 30) {log.info("****************************同步回调处理中****************************");resultMap.put("ret_code", "1005");resultMap.put("ret_msg", "支付处理失败");return ;}
// TODO 逻辑处理
    // 删除锁文件 RechargeUtil.deleteOnlyFile(rpmtIds, "01"); 
}

 更改成“还款中”的时候:

/*** 将还款计划该成还款中* @Title: updateRpmt * @param rpmtIdsStr* @throws Exception */public void updateRpmting(String[] rpmtIdsStr,String rpmtIds) throws Exception{//创建一个唯一文件int size = 0;while (size < 30 && !RechargeUtil.creatOnlyFile(rpmtIds,"02", "01")) {Thread.sleep(100);size++;}if (size >= 30) {log.info("****************************状态处理中****************************");return ;}// TODO 逻辑处理// 删除锁文件RechargeUtil.deleteOnlyFile(rpmtIds, "02");}

 

转载于:https://www.cnblogs.com/mark8080/p/6201763.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/489348.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

从生态、业绩角度分析芯片行业

来源&#xff1a;国信证券生态角度&#xff1a;合作伙伴、底层架构、高级人才、EDA 软件技术的发展是从点到面&#xff0c;逐渐复杂。产业的发展也是从单一点突破&#xff0c;最后形成上下游产业链。伴随着技术变复杂和产业链延伸&#xff0c;市场形成稳定的生态结构&#xff0…

param注解报错_mybatis不加@Parm注解报错的解决方案

我的idea版本2017.3.4,低版本貌似不会加上这个配置,idea高版本会补充知识&#xff1a;Mybatis传多个参数的问题 及MyBatis报错 Parameter 0 not found. Available parameters are [arg1, arg0, param1 问题对于使用Mybatis ,传多个参数&#xff0c;我们可以使用对象封装外&…

tensorflow计算网络占用内存_详细图解神经网络梯度下降法(tensorflow计算梯度)...

1.什么是梯度各个方向的偏微分组成的向量​ 举例说明&#xff0c;z对x的偏微分和对y的偏微分如下&#xff0c;则梯度是&#xff08;-2x&#xff0c;2y&#xff09;的这样一个向量​ 在光滑连续函数的每个点上&#xff0c;都可以计算一个梯度&#xff0c;也就是一个向量&#xf…

ztree插件的使用

在bootstrap中使用ztree插件做树形架构&#xff0c;由于觉得原始的树形不够美观&#xff0c;所以改了其中的css插件 demo演示,以及各种属性的用法网站&#xff1a; http://www.treejs.cn/v3/demo.php#_107 修改页面风格网站&#xff1a; http://www.lai18.c…

耐驰测试仪上的软件,Proteus

Proteus - 扩展功能Proteus 软件的基本配置已经包含热分析各领域的所有主要功能。对于一些扩展性的测量与分析&#xff0c;我们提供下列可选组件&#xff1a;宏记录器使用事先录制的宏操作命令&#xff0c;对于相似的一系列常规测试结果进行自动分析&#xff0c;自动分析结果还…

关于数据中台系统,需要了解哪些技术?

来源&#xff1a;国家建材大数据研究中心今天让我们全面解读中台&#xff0c;包括企业为什么要平台化&#xff0c;目前中台都有哪些形式&#xff0c;实施中台系统的优势、面临的问题以及建议都有哪些&#xff1f;中台这个概念早期是由美军的作战体系演化而来的&#xff0c;技术…

ios请求头解决参数中文乱码_花了一天时间就解决了一个的请求头传参参数格式bug...

一天的时间就解决了一个bug就这么过去了&#xff0c;但不能让他就这么过去了&#xff0c;加班要加的有价值&#xff0c;所以现在记录一下这一天的经历&#xff0c;以防下次再踩坑大致说下我的情况&#xff0c;入坑的不久的前端新手&#xff0c;在做一个项目的重构&#xff0c;用…

python for循环连续输入五个成绩判断等级_Python条件循环判断

1.条件判断语句 Python中条件选择语句的关键字为&#xff1a;if 、elif 、else这三个。其基本形式如下&#xff1a; 1 2 3 4 5 6 7 8 9 age_of_cc 27 age int(input("guessage:")) if age age_of_cc: print("Yes,you got it!") elif age > age_of_cc: p…

用注册表禁止windows添加新用户

运行 regedt32.exe 打开你的注册表&#xff0c;里面有一个目录树&#xff1a;打开其中目录 HKEY_LOCAL_MACHINE再打开其中目录 SAM再打开其中目录 SAM再打开其中目录 Domains再打开其中目录 Account再打开其中目录 Groups好了&#xff0c;就是这个 Groups 就是负责建立用户的。…

显示当前没有家庭组计算机,已创建家庭组且加入家庭组,但显示“当前没有其他可用的家庭组计算机?”...

出现的问题&#xff1a;无法查询家庭组其他可用的计算机情况&#xff1a;1、家里一台WIN7 旗舰版&#xff0c;一台WIN7 家庭普通版2、在 旗舰版 电脑创建了家庭组&#xff0c;并在另一台输入密码&#xff0c;且成功加入加家庭组3、在 电脑控制面板中&#xff0c;“网络”里&…

人工智能的下半场,一定少不了自监督学习

来源&#xff1a;AI科技评论作者 | Lilian Wang 王荔编译 | MrBear对于给定的任务&#xff0c;在拥有足够的标签的情况下&#xff0c;监督式学习可以很好地解决该问题。想要得到好的性能&#xff0c;往往需要大量的数据标签&#xff0c;但是手动收集数据的成本很高&#xff08;…

bert 多义词_BERT之后,GLUE基准升级为SuperGLUE:难度更大

选自Medium作者&#xff1a;Alex Wang等机器之心编译参与&#xff1a;PandaBERT 等模型的进展已让 GLUE 基准在新模型的评估方面日渐乏力&#xff0c;为推动 NLP 技术的进一步发展&#xff0c;有必要对 GLUE 指标进行更新。为此&#xff0c;纽约大学、Facebook 人工智能研究所、…

thread.sleep是让哪个线程休眠_Java多线程:多线程基础知识

点击上方☝SpringForAll社区 轻松关注&#xff01;及时获取有趣有料的技术文章本文来源&#xff1a;https://www.cnblogs.com/ITtangtang/p/7602363.html一、线程安全性定义&#xff1a;多个线程之间的操作无论采用何种执行时序或交替方式&#xff0c;都要保证不变性条件不被破…

拉格朗日插值函数计算机实现流程图,拉格朗日插值实验报告.doc

实验名称&#xff1a; 实验一 拉格朗日插值引言我们在生产生活中常常会遇到这样的问题&#xff1a;某个实际问题中&#xff0c;函数f(x)在区间[a,b]上存在且连续&#xff0c;但找到其表达式&#xff0c;只能通过实验和观测得到有限点上的函数表。有些情况虽然可以写出表达式&am…

整个领域没了!学术界有史以来最大的丑闻

来源&#xff1a;中大科技处10月15日&#xff0c;学术界发生了一件大事。哈佛终身教授学术造假&#xff0c;31篇文献被撤&#xff0c;无数研究化为泡影……哈佛一次性从各类顶尖期刊上撤稿了31篇论文&#xff0c;整个心肌干细胞相关的研究被认定为“从一开始就基于欺诈性数据”…

布隆过滤器误判怎么办为什么会_最牛一篇布隆过滤器详解,布隆过滤器使用原理...

前言我们之前讲了Redis的缓存雪崩、穿透、击穿。在文章里我们说了解决缓存穿透的办法之一&#xff0c;就是布隆过滤器&#xff0c;但是上次并没有讲如何使用布隆过滤器。作为暖男的老哥&#xff0c;给你们补上&#xff0c;请叫我IT老暖男。什么是布隆过滤器布隆过滤器(Bloom Fi…

thinkPHP-空操作

空操作 当访问的方法不存在时&#xff0c;可以定义一个empty方法来避免空操作 function _empty(){echo "网页不存在&#xff0c;请检查地址信息";} 这样当访问不存在的方法时就会显示以上信息 当访问的控制器不存在时&#xff0c;可以定义一个空操作器 <?php nam…

python3 面向对象_Python3 面向对象

Python和C都是一门面向对象的语言&#xff0c; 面向对象技术简介 类(Class):用来描述具有相同的属性和方法的对象的集合。它定义了该集合中每个对象所共有的属性和方法。对象是类的实例。比如 f file()##创建了一个类(file())的对象f 类变量&#xff1a;类变量在整个实例的对象…

口腔ct重建服务器原理,牙科CT是什么?牙科CT的原理及优势介绍

原标题&#xff1a;牙科CT是什么&#xff1f;牙科CT的原理及优势介绍牙科CT是什么&#xff1f;牙科CT&#xff0c;又称口腔CT&#xff0c;是一种新型牙科类仪器&#xff0c;它可以从三维角度对口腔部组织情况进行扫描检查。牙科CT在业界被誉为神奇的“慧眼”&#xff0c;它犹如…