【发布时间】: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