簡體   English   中英

MySQL / MariaDB InnoDB同時交易和鎖定行為

[英]MySQL/MariaDB InnoDB Simultaneous Transactions & Locking Behaviour

作為我的一個模型中持久化過程的一部分,生成整個記錄的md5 check_sum並與記錄一起存儲。 md5 check_sum包含整個記錄的展平表示,包括所有EAV屬性等。這使得防止絕對重復變得非常容易和有效。

由於特定原因,我沒有在此check_sum上使用唯一索引,我希望這一切都是靜默的,即如果用戶提交副本,則應用程序只是默默地忽略它並返回已存在的記錄。 這確保了與傳統應用程序和api的向后兼容性。

我正在使用Laravel的雄辯。 因此,一旦創建了記錄,並且在提交應用程序之前執行以下操作:


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

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

然而最近我遇到了60,000 / 1次射擊事件(根據當時的記錄數計算的賠率)。 單個副本最終在數據庫中以相同的check_sum結束。 當我查看日志時,我注意到創建時間與第二個相同。 對Apache日志的進一步調查顯示了有效的POST,但POST是重復的。 我認為用戶瀏覽器出現故障或者兩個POSTS同時到達,導致兩個同時發生的事務。

我的問題是如何確保事務及其包含的前一個check_sum的SELECT是Atomic&Isolated。 根據我的閱讀,答案在於https://dev.mysql.com/doc/refman/8.0/en/innodb-locking-reads.html和隔離級別。

如果事務A和事務B同時到達服務器,則它們不應並行運行,而應等待第一個完成。

你創造了一個經典的競爭條件 兩個事務都在計算校驗和,但它們都在進行中,尚未提交。 兩者都無法讀取其他數據,因為它們是未提交的。 所以他們計算出他們是唯一一個具有相同校驗和的人,他們都經歷並提交。

要解決此問題,您需要以串行方式運行此類事務,以確保沒有其他並發事務提交相同的數據。

在開始事務之前,您可能必須使用GET_LOCK()來計算校驗和。 提交后再使用RELEASE_LOCK() 這將確保其他並發請求等待您的數據提交,因此他們將在嘗試計算其校驗和時看到它。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM