【问题标题】:MySQL/MariaDB InnoDB Simultaneous Transactions & Locking BehaviourMySQL/MariaDB InnoDB 同步事务和锁定行为
【发布时间】:2019-06-25 13:37:59
【问题描述】:

在我的一个模型中,作为持久性过程的一部分,会生成整个记录的 md5 check_sum 并与记录一起存储。 md5 check_sum 包含整个记录的扁平表示,包括所有 EAV 属性等。这使得防止绝对重复非常容易和有效。

出于特定原因,我没有在此 check_sum 上使用唯一索引,我希望这一切都保持沉默,即如果用户提交重复项,则应用程序会默默地忽略它并返回已经存在的记录。这确保了与旧版应用程序和 api 的向后兼容性。

我正在使用 Laravel 的 eloquent。因此,一旦创建了记录并在提交应用程序之前执行以下操作:


            $taxonRecords = TaxonRecord::where('check_sum', $taxonRecord->check_sum)->get();

            if ($taxonRecords->count() > 0) {
                DB::rollBack();
                return $taxonRecords->first();
            }

但是最近我遇到了 60,000/1 次射击事件(赔率基于当时的记录计数)。一个副本最终以相同的校验和出现在数据库中。当我查看日志时,我注意到创建时间与第二个相同。对 Apache 日志的进一步调查显示 POST 有效,但 POST 重复。我认为用户浏览器出现故障或其他原因,但两个 POSTS 同时到达,导致两个同时交易。

我的问题是如何确保之前 check_sum 的事务及其包含的 SELECT 是原子和隔离的。根据我的阅读,答案在于https://dev.mysql.com/doc/refman/8.0/en/innodb-locking-reads.html 和隔离级别。

如果事务 A 和事务 B 同时到达服务器,那么它们不应并行运行,而应等待第一个完成。

【问题讨论】:

  • “我认为用户浏览器出现故障或其他原因,但两个 POSTS 同时到达,导致两个同时交易。” 听起来更像是用户双击而不是一次并提交表单两次

标签: mysql transactions locking mariadb innodb


【解决方案1】:

您创建了经典的race condition。两个事务都在计算校验和,而它们都在进行中,尚未提交。两者都无法读取对方的数据,因为它们未提交。所以他们计算出他们是唯一具有相同校验和的人,并且他们都通过并提交。

要解决这个问题,您需要串行运行此类事务,以确保没有其他并发事务提交相同的数据。

您可能必须在开始交易之前使用GET_LOCK() 来计算校验和。然后在你提交之后RELEASE_LOCK()。这将确保其他并发请求等待您的数据提交,以便他们在尝试计算校验和时看到它。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-04-29
    相关资源
    最近更新 更多