作为我的一个模型中持久性过程的一部分,将生成整个记录的md5 check_sum并将其与记录一起存储。 md5 check_sum包含整个记录的展平表示,包括所有EAV属性等。这使得防止绝对重复非常容易和有效。
出于特定原因,我没有在此check_sum上使用唯一索引,我希望所有这些都保持沉默,即,如果用户提交了重复项,则应用程序会默默地忽略它并返回已经存在的记录。这样可以确保与旧版应用程序和api的向后兼容性。
我正在使用Laravel的口才。因此,一旦创建了记录并在提交应用程序之前执行以下操作:
{{ 2019-06-26T19:31:00.000Z | date:"HH:mm"}}
但是最近我遇到了60,000 / 1次枪击事件(根据当时的记录数,赔率很高)。单个重复项最终以相同的check_sum出现在数据库中。当我查看日志时,我注意到创建时间与第二次相同。对Apache日志的进一步调查显示有效的POST,但该POST是重复的。我认为用户浏览器发生故障或什么原因,但两个POST同时到达,导致两个同时发生的事务。
我的问题是我如何确保上一个check_sum的事务及其包含的
$taxonRecords = TaxonRecord::where('check_sum', $taxonRecord->check_sum)->get();
if ($taxonRecords->count() > 0) {
DB::rollBack();
return $taxonRecords->first();
}
是Atomic&Isolated。根据我的阅读,答案在于https://dev.mysql.com/doc/refman/8.0/en/innodb-locking-reads.html和隔离级别。
如果事务A和事务B同时到达服务器,则它们不应并排运行,而应等待第一个完成。
答案 0 :(得分:0)
您创建了经典的race condition。这两个事务都在进行中但尚未提交,它们都在计算校验和。由于未提交,因此任何一方都无法读取对方的数据。因此,他们计算出自己是唯一具有相同校验和的人,并且他们都经过并提交。
要解决此问题,您需要连续运行此类事务,以确保没有其他并发事务提交相同的数据。
在开始事务计算校验和之前,您可能必须使用GET_LOCK()。然后在提交后RELEASE_LOCK()。这样可以确保其他并发请求都等待您的数据被提交,这样他们在尝试计算校验和时就会看到它。