【问题标题】:How to Implement Cross-Session Request Locking.如何实现跨会话请求锁定。
【发布时间】:2018-07-23 12:11:40
【问题描述】:

我有一个 Grails 应用程序,它执行 API 调用、获取回复、处理回复中的数据,然后在结果页面上显示一些图表。

用户输入一些数据并点击一个按钮来执行。因此,如果两个用户同时或几乎同时单击该按钮,则如果没有实施任何锁定,那么其中一个或两个都可能最终导致结果页面上没有显示任何结果。我需要防止这种情况发生,最好让第二个请求等到 grails 执行第一个请求。

我读过关于乐观与悲观锁定的文章,但没有什么能真正解释如何实现它以及在哪里实现它。在控制器中?在服务?

是这样的电话吗?在哪里?

 myInstance.save flush:true, failOnError: true

感谢您对理解这一点的任何帮助,我无法找到关于此的大量信息。

【问题讨论】:

    标签: grails


    【解决方案1】:

    您需要实现跨会话请求锁定。

    最简单的方法是使用单例映射来防止并行执行请求。这可能看起来像:

    class LockingSomethingController {
      static scope = "singleton"
    
      Map locks = new ConcurrentHashMap()
    
      def lockMe( String id ) {
        if( locks[ id ] ){
          render status:400, text:'locked'
          return
        }
        locks[ id ] = true
        try{
          doSomeSeriousStuff()
        }finally{
          locks.remove id
        }
      }
    }
    

    【讨论】:

    • 好的,我导入了 import java.util.concurrent。我将它添加到处理 api 事务执行的方法中,它似乎没有做任何事情,所以我一定做错了什么。我假设 id 是一些独特的强项,例如 sysId,我使用的是 myInstance.id。
    • id 应该是您尝试锁定的资源的 ID。它可能是某个域对象的 id,或者是动作的静态名称,如果后者应该以独占方式执行。如果需要锁定单个资源,可以将ConcurrentHashMap替换为AtomicBoolean
    • 这是在控制器还是服务中?
    • 由您决定。如果它仍然简单,则将其留在控制器中,当它变得更复杂并且应该重用时,将其移动到服务中
    • 您只想将控制器设为单例,我认为这不是一个好的解决方案,最好将逻辑导出到服务中。
    猜你喜欢
    • 1970-01-01
    • 2013-12-17
    • 2017-04-21
    • 1970-01-01
    • 1970-01-01
    • 2015-03-03
    • 2013-10-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多