2012-02-17 110 views
1

我有一個簡單的電力系統之間轉移信用分數,因爲用戶可以借到對方:Mysql的交易,用戶

mysql_query("INSERT INTO power (sender, receiver, amount) 
    VALUES ('$sender', '$receiver', '$amount')"); 
mysql_query("UPDATE users SET power=power-$amount WHERE user_id='$sender'"); 
mysql_query("UPDATE users SET power=power+$amount WHERE user_id='$receiver'"); 

我檢查,如果發送方有足夠的信用額度由SELECT查詢運行上文前轉移上述一組查詢。

問題1:我認爲,最好把所有這四個查詢放到一個Transaction;因爲InnoDB ACID將保證更安全的性能。什麼是最好的交易呢?

問題2:功率爲unsigned int。如果有機會(甚至不太可能),用戶沒有足夠的信用額度power-$amount將不會設置0;相反,它將循環通過int()的最大值,即4294967295.這意味着用戶將被授予幾乎無限的權力(信用)。

回答

3

首先,不同意這種麻煩:

我檢查,如果發送方有足夠的信用額度由SELECT查詢運行上述設定的查詢之前轉移。

這會讓你面對一場無論如何都必須面對的競爭狀況。相反,請在數據庫中設置約束條件,使其無法進入無效狀態。

第2期:功率爲unsigned int

不要這樣做,沒有必要。一個4字節的有符號整數在正方面應該有足夠的空間;如果沒有,你可以切換到一個有符號的8字節整數。你想要一個有符號值的原因是它使得完整性檢查非常容易:如果一個平衡值降到零以下,那麼就是錯誤的。如果使用無符號值,則必須保留4294967295-n(對於某些n)來檢測下溢和溢出,而不是簡單的< 0

至於限制你的數據而言,通常你會使用一個CHECK約束這樣的:

check (power >= 0) 

但MySQL不支持CHECK約束。但是,您可以編寫一個BEFORE INSERT或UPDATE觸發器,它可以檢查它是否爲new.power >= 0raise an exception

現在你有一個users表不允許無效power值,以便我們與問題2.

上完成發行1:交易。是的,你絕對想要使用transaction進行轉賬。你會想這樣的順序:

  1. start transaction
  2. INSERT INTO power (sender, receiver, amount) VALUES ('$sender', '$receiver', '$amount')
  3. UPDATE users SET power=power-$amount WHERE user_id='$sender'
  4. UPDATE users SET power=power+$amount WHERE user_id='$receiver'
  5. 是否有過由 「檢查觸發」 任何錯誤?
    • 如果有,然後發送rollback到數據庫並告訴用戶出了什麼問題。
    • 如果還沒有發送commit到數據庫。

本次交易將確保所有三個操作將成功或失敗作爲一個單元和CHECK約束(如觸發器來實現),確保沒有人可以放棄比他們擁有更多的權力。

+0

非常翔實的答案...我學到了很多! – Googlebot 2012-02-17 08:33:19

+0

@Ali:很酷,這就是爲什麼我們都在這裏:) – 2012-02-17 08:48:30