Mysql

如何確保只檢索一次記錄

  • February 26, 2018

如果我有一個名為 Coupons 的表,其中包含 10,000 條記錄。我應該如何設計架構或應該使用什麼查詢,以便我的 API 永遠不會兩次獲得相同的記錄。如果我只是向數據庫詢問最後一條記錄,我認為另一個實例可能會同時向數據庫詢問該記錄。

我應該研究記錄鎖定嗎?這對性能有什麼影響嗎?該表將被大量訪問。由於有 10,000 條記錄,如果某些記錄被鎖定是可以的,因為數據庫可以返回未鎖定的記錄。

Coupon到目前為止的表只是

id [int]
coupon [varchar]
project [int](fk to projects table)

mysql 5.6

編輯:我只是提供優惠券。一旦我從數據庫中提取,它就被認為對我來說已經習慣了。我也沒有身份證可以查。我想從字面上重新創建 DMV 的售票機,讓人們按照服務對象的順序排列。一旦一個號碼被拉出來,其他人就不會得到那個號碼。我擔心程式碼是否嘗試同時選擇最後一張優惠券併兩次給出相同的號碼。

我假設這是以下情況:

  • 您可以多次查找優惠券(例如:驗證優惠券是否存在)
  • 一旦您使用優惠券,優惠券將失效

最簡單的方法是呼叫兩個欄位isUsed intExpirationDate datetime 然後創建兩個執行以下操作的 API:

  • CheckCoupon(優惠券ID)

這將對照表檢查優惠券id, ExpirationDate, isUsed。如果儲存過程返回 1,則優惠券有效,否則無效。

創建一個名為usp_check_coupon

SELECT count(*) 
FROM Coupon
Where id = @id
and ExpirationDate > [today's_date]
and IsUsed = 0
  • UseCoupon(優惠券ID)

將優惠券標記為已使用。在更新IsUsed為 1 之前,請檢查以確保IsUsed為 0。

創建一個名為usp_use_coupon

DECLARE @isused int =
   SELECT count(*) 
   FROM Coupon 
   Where id = @id
   and ExpirationDate > [today's_date]
   and IsUsed = 0

IF (@isused == 1)
BEGIN
   UPDATE COUPON
   SET IsUsed = 1
   WHERE ID = @id

  SELECT 1 --Updated Successfully
END

SELECT 0 --Updated Failed

然後在API上,如果usp_use_coupon返回0,則表示優惠券已使用或過期。如果為 1,則已處理。

在研究了隔離級別和事務之後,我想出了以下解決方案。目前未經測試,但理論應該是正確的。

我的 API (nodeJS) 將執行以下事務:

START TRANSACTION;
SELECT @1:=id as id, @2:=coupon as coupon FROM coupons WHERE isUsed = 0 LIMIT 1 FOR UPDATE;
UPDATE coupons SET isUsed = 1 WHERE id = @1 AND isUsed = 0;
COMMIT;

這個想法是寫鎖定該行,然後更新為,isUsed因為一旦我發送優惠券,它就被認為是我習慣了。由於另一個程序可以同時讀取同一行,因此它不會知道更新。但是因為我們已經鎖定了行,所以只有 1 個程序能夠更新 1 行影響的結果。如果 UPDATE 查詢導致 0 行受影響或錯誤,則 API 將重試獲取另一個優惠券,因為它嘗試更新已使用的優惠券或被阻止寫入。

引用自:https://dba.stackexchange.com/questions/198701