与 DB 和 URL 交互的并发处理

Posted

技术标签:

【中文标题】与 DB 和 URL 交互的并发处理【英文标题】:Concurrency handling with DB and URL interaction 【发布时间】:2015-11-10 21:14:28 【问题描述】:

我有一个计费应用程序,如果客户已经付款,它会在数据库中进行请求检查,如果没有付款,它会点击计费 API,然后更新数据库中的响应。

当客户通过单击“计费”按钮 3-4 次多次发送请求时,我遇到了问题。所有请求都以毫秒为单位到达服务器。结果,客户被多次收费,因为结果没有得到更新,因为第一个请求需要一些时间,同时第二个请求从数据库中读取状态并再次进行收费。下面是代码。请让我知道我应该遵循哪些最佳实践来防止这种情况发生。我试过制作servlet SingleThreadModel,但没有帮助

 protected void processRequest(HttpServletRequest request, HttpServletResponse response)
         throws ServletException, IOException 
    response.setContentType("text/html;charset=UTF-8");
    try (PrintWriter out = response.getWriter()) 
        /* TODO output your page here. You may use following sample code. */
        String mobilenumber = request.getParameter("mobilenumber");
        String param2 = request.getParameter("param2");
        String checkifthecustomerischarged = checkifcharge(mobilenumber);
        if (checkifthecustomerischarged.equals("NOTOK")) 
            String status = hittocharge(mobilenumber, param2);
            int i = updatestatus(mobilenumber, status);
            if (i > 0) 
                out.println("Status Updated ");
             else 
                out.println("Status Not update Updated ");
            
         else 
            out.println("Already Charged");
        
      
  

我在这里查看表格

 private String checkifcharge(String mobilenumber) 
    String st = "NOTOK" ; 
    try 
        Connection conn = null ; 
        ResultSet rs  = conn.createStatement.executeQuery("select sno from table where mobilenumber = "+mobilenumber);
       if(rs.next())
       st = "OK";
       

     catch (Exception e) 
        e.printStackTrace();
     
  return st ;
  

我在这里更新状态

   private int updatestatus(String mobilenumber, String status) 
    int st = 0 ; 
    try 
        Connection conn = getConnection() ; 
       st  = conn.createStatement.executeQuery("update table set status =1    where  mobilenumber ="+mobilenumber);

       releaseConnection(conn);
     catch (Exception e) 
        e.printStackTrace();
    
 return st ;

【问题讨论】:

我真诚地希望这是代码不用于实际计费。 实际上这不是现场直播,我正在尝试制作一个.. 让我知道您对此的想法。 我觉得你太缺乏经验了。计费涉及金钱,没有人会相信不能正确处理交易的软件。 【参考方案1】:

通常,人们不仅会说“给我开账单”,还会说“为特定的事情给我开账单”(例如“2015 年 8 月为手机号码 123 付款”)。我会决定每个账单的标识符(例如“08_2015_123”)并将其包含在账单请求和状态表中。然后你可以使用乐观更新,这是在

行中的东西
st=statement.executeQuery("update table set status=1 where identifier='08_2015_123' and status<>1")
// if st==0 it probably means bill was previously payed, don't bill again

顺便说一句,即使您绝对确定不能生成这样的标识符,您也可以始终在表单中生成一些虚拟随机字段,这样至少您可以识别对同一个按钮的多次快速点击(尽管它赢了对更复杂的情况没有帮助,例如忘记他一周前付款的用户)。但是,在计费时,我会努力寻找合适的标识符。

【讨论】:

嗨 pelit,感谢您的回复,但我希望在这里添加同步、线程安全、单线程模型生活功能,但仍有一些计费模型,只需点击他的移动帐户即可直接收费。 您好,如果问题来自mobile 上的多次点击,我担心悲观锁定(同步/线程安全等)将无济于事。考虑一下...您将锁定什么以及何时锁定?就像锁定的触发器应该是“我在移动设备上渲染按钮的那一刻”,这将是一场性能噩梦。 顺便说一句,如果您正在寻找快速解决方案,只需单击多次,您可以在第一次单击后(以及在发送我们的请求之前)禁用该按钮。但我觉得从大局来看,最好能够确定您的计费对象。 不,我们无法控制点击,因为有时它是一个按钮,有时是横幅,我们只是将 url 提供给第三方,他们打得很糟糕,保持块 syn 没有帮助,也没有保留 servlet实现单线程模型.. 是的,您可能意识到这是因为您仍然收到多个请求,因此即使您对所有内容都进行悲观锁定 - 它只会让它们按顺序运行...这就是为什么我认为您需要乐观锁定。也许在您的情况下,执行“update table set status=1 where mobileNumber=123 AND status1”就足够了,如果返回 0,则表示不应该计费的重复项。

以上是关于与 DB 和 URL 交互的并发处理的主要内容,如果未能解决你的问题,请参考以下文章

精通Java事务编程-总结

Java并发基础--volatile关键字

CPU缓存机制 并发编程的基础

并发与并行

多处理:优化并发 HTTP 异步请求的 CPU 使用率

并发与并行的区别