我正在尋找一個解決方案:如何處理併發風險任務?
function foo()
{
client 1 executes an update/delete
// client 2 calls foo() and breaks data integrity
client 1 executes an update/delete
}
我該如何解決這個與MySQL?我使用的是myisam表,但我對innodb的解決方案也很感興趣。
我正在尋找一個解決方案:如何處理併發風險任務?
function foo()
{
client 1 executes an update/delete
// client 2 calls foo() and breaks data integrity
client 1 executes an update/delete
}
我該如何解決這個與MySQL?我使用的是myisam表,但我對innodb的解決方案也很感興趣。
注意:這個答案假設你是InnoDB,它允許行級鎖定,而不是需要表鎖的MyISAM。
對於這樣的情況,您可以使用事務和READ/WRITE鎖。您需要的具體細節因案例而異,如果不知道您的模式和您擔心的數據完整性,我無法回答,所以我會給您一個一般的解釋。
可以在您不打算寫入的行上獲取讀取鎖定,但在您的事務處理期間不得更改。可以在您打算在未來的某個時間點更改的行上獲取寫入鎖定。事務是一系列多個操作,以全有或全無的方式應用於數據庫。
因此,作爲一個例子可以假設以下幾點:
你會做這樣的事情:
// This makes it so that each operation is not automatically commited (saved)
// It implicitly makes all sequences of operations into transactions
execute("set autocommit=0");
// This gets you some data from table_B and also gets a read lock to prevent that data from changing
result = execute("SELECT * FROM `table_B` WHERE `condition` = 1 LOCK IN SHARE MODE");
// This gets some data from table_C and gets a write lock to prevent the data from changing and allowing you to write to it in the future
result2 = execute("SELECT * FROM `table_C` WHERE `condition` = 1 FOR UPDATE");
// This performs your update to table_A
execute("UPDATE `table_A` SET `value` = 1234 WHERE `condition` = 1");
// This performs your update to table_C
execute("UPDATE `table_C` SET `value` = 4321 WHERE `condition` = 1");
// This saves all of the changes that you made during your transaction and releases all locks
// Note: autocommit is still turned off
execute("COMMIT");
所以讓有涉及購買一些更具體的例子。我意識到這可以通過一個更新語句完成,但我正在通過這種方式來說明如何使用事務。
我的表是:
items (id int not null primary key, user_id int not null, item_type int not null)
accounts (user_id int not null primary key, balance int not null)
prices (item_type int not null primary key, price int not null)
limits (item_type int not null primary key, max_count int not null)
注意,我要跳過爲簡潔起見輸入環境衛生,不這樣做,真的。 (http://xkcd.com/327/)
function purchase(user_id, item_type) {
execute("set autocommit=0");
// I am assuming that price and max_count can be changed but they require consistency with each other hence the read locks
var price = execute("SELECT `price` FROM `prices` WHERE `item_type` = " + item_type + " LOCK IN SHARE MODE")[0].price;
var max_count = execute("SELECT `max_count` FROM `limits` WHERE `item_type` = " + item_type + " LOCK IN SHARE MODE")[0].max_count;
// I need the write lock to prevent double spending
var account = execute("SELECT * FROM `accounts` WHERE `user_id` = " + user_id + " FOR UPDATE")[0];
// I need to guarantee that the user is not over the limit
var count = execute("SELECT count(*) AS `count` FROM `items` WHERE `user_id` = " + user_id + " FOR UPDATE")[0].count;
var new_balance = account.balance - price;
if(count >= max_count || new_balance < 0) {
return false;
}
execute("INSERT INTO `items` (`user_id`, `item_type`) VALUES (" + user_id + ", " + item_type + ")");
execute("UPDATE `accounts` SET `balance` = " + new_balance + " WHERE `user_id` = " + user_id);
execute("COMMIT");
return true;
}
還應該注意的是,你現在不用擔心死鎖,但是這是一個完全獨立的主題。
如果您可以提供一些架構和您擔心的數據完整性的示例,這將會很有幫助。這允許推薦更多更具體的解決方案。 –
查詢1驗證父母身份證,查詢2引用父母身份證在另一行...之間的兩個第二任務刪除父母身份證的行... – sveva