【问题标题】:Double-click double-insert resolutions?双击双插入分辨率?
【发布时间】:2017-12-13 11:24:07
【问题描述】:

团队成员在使用旧的内部系统时遇到了问题,其中用户双击网页上的链接可能会导致从浏览器发送两个请求,从而导致同一记录的两个数据库插入处于比赛状态;最后一个运行失败,主键违规。已经提出并讨论了几种解决方案和技巧:

  1. 在网页上使用 Javascript 通过禁用第一次点击时的链接来减少第二次点击。这是一种快速简便的方法,可以减少问题的发生,但不能完全消除问题。

  2. 将服务器端的请求执行包装在事务中。由于相关表上的服务器负载和锁定级别,这被认为过于昂贵。

  3. 捕获失败插入引发的主键异常,将其识别为主键异常,然后吃掉它。这样做的缺点是 (a) 供应商锁定,必须知道特定于数据库的异常的细微差别,以及 (b) 可能不记录/处理合法的数据库故障。

  4. #3 的扩展,在插入失败时尝试更新记录并检查更新结果以确保它返回 1 条受影响的记录。

还有没有考虑过的其他选项?被忽视的选项是否有优缺点?万恶之中,孰轻孰重?

【问题讨论】:

    标签: insert primary-key double-click


    【解决方案1】:

    在页面上的隐藏字段中放置唯一标识符。只接受一个具有给定唯一标识符的响应。

    【讨论】:

    • 这在服务器端增加了很多开销——在一个服务器群中,他们都必须知道这个标识符,他们都必须同步并锁定它,所以没有如果两个请求在两个不同的服务器上平衡,则出现竞争条件。
    • 如果唯一标识符是数据库插入的主键,那么您的数据库完整性将会处理它。
    【解决方案2】:

    听起来您可能误用了 GET 请求来修改服务器状态(尽管不一定是这种情况)。虽然它可能不适合您的情况,但应该说明您应该考虑将链接转换为 POST 表单。

    【讨论】:

      【解决方案3】:

      您需要实现同步器令牌模式。

      它的工作原理是:在服务器上为每个请求生成一个值(令牌)。然后必须在您的表单提交中包含相同的令牌。收到请求后,将比较服务器令牌和客户端令牌,如果它们相同,您可以继续添加您的记录。然后重新生成服务器端令牌,因此包含旧令牌的后续请求将失败。

      关于中途下降this page有更详尽的解释。

      我不确定您使用的是什么技术,但 Struts 为这种模式提供了框架级别的支持。见例子here

      【讨论】:

      • 虽然这似乎是措辞最好、最深思熟虑的回应,但在令牌检查和新令牌生成之间仍然存在竞争条件;必须以某种方式同步。
      • 如果新令牌在每个页面视图上重新生成,并存储在某种可以锁定而不会降低性能的数据库中,则不会。现在你可以锁定数据库,检查该值是否已经被使用,然后巧妙地错误输出,如果它没有被使用,标记它使用并调用它完成
      【解决方案4】:

      您似乎已经在那里回答了您自己的问题; #1 似乎是唯一可行的选择。

      否则,您应该真正完成所有三个步骤 - 数据完整性应在数据库级别处理,但在代码中进行额外检查(例如显式事务)以避免往返数据库可能对性能有好处。

      【讨论】:

        【解决方案5】:

        REF 你需要实现 Synchronizer Token 模式。

        这是针对 Javascript/HTML 而不是 JAVA 的

        【讨论】:

          猜你喜欢
          • 2014-12-13
          • 1970-01-01
          • 2013-06-14
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-02-28
          • 1970-01-01
          相关资源
          最近更新 更多