我認爲最好的方式來處理,這將是使用SELECT ... FOR這裏描述的更新模式:http://dev.mysql.com/doc/refman/5.0/en/innodb-locking-reads.html
參考:
Let us look at another example: We have an integer counter field in a table child_codes that we use to assign a unique identifier to each child added to table child. It is not a good idea to use either consistent read or a shared mode read to read the present value of the counter because two users of the database may then see the same value for the counter, and a duplicate-key error occurs if two users attempt to add children with the same identifier to the table.
Here, LOCK IN SHARE MODE is not a good solution because if two users read the counter at the same time, at least one of them ends up in deadlock when it attempts to update the counter.
To implement reading and incrementing the counter, first perform a locking read of the counter using FOR UPDATE, and then increment the counter. For example:
SELECT counter_field FROM child_codes FOR UPDATE; UPDATE child_codes
SET counter_field = counter_field + 1;
A SELECT ... FOR UPDATE reads the latest available data, setting exclusive locks on each row > it reads. Thus, it sets the same locks a searched SQL UPDATE would set on the rows.
。 。 。
Note Locking of rows for update using SELECT FOR UPDATE only applies when autocommit is disabled (either by beginning transaction with START TRANSACTION or by setting autocommit to 0. If autocommit is enabled, the rows matching the specification are not locked.
所以你的情況,你將取代
LOCK TABLES AlarmCount WRITE, AlarmMembership READ;
UPDATE AlarmCount SET num = num - 1
WHERE RuleId = OLD.RuleId AND
MemberId = 0 AND
IsResolved = OLD.IsResolved;
的東西,如
SELECT num FROM AlarmCount WHERE RuleId = OLD.RuleId AND
MemberId = 0 AND
IsResolved = OLD.IsResolved FOR UPDATE;
UPDATE AlarmCount SET num = num - 1;
我說「像」,因爲它並不完全清楚,我什麼OLD.RuleId和OLD.IsResolved是引用。另外值得一從http://dev.mysql.com/doc/refman/5.0/en/innodb-locking-reads.html關注的是:
The preceding description is merely an example of how SELECT ... FOR UPDATE works. In MySQL, the specific task of generating a unique identifier actually can be accomplished using only a single access to the table:
UPDATE child_codes SET counter_field = LAST_INSERT_ID(counter_field +
1);
SELECT LAST_INSERT_ID();
The SELECT statement merely retrieves the identifier information (specific to the current connection). It does not access any table.
換句話說,你也許可以進一步訪問只是一次表優化這種模式......但同樣是關於您的架構的一些細節,我不太明白,我不確定我能否提供你需要的實際陳述。我認爲,如果你看一下SELECT ... FOR UPDATE,你會發現這個模式歸結爲什麼,以及你需要做什麼才能在你的環境中實現這個功能。
我應該提及的是,有一些存儲引擎環境和事務隔離級別您需要考慮。關於這個話題,SO在這裏有非常非常好的討論:When to use SELECT ... FOR UPDATE?
希望這有助於!
我最終鎖定了調用者代碼,因此避免了潛在的衝突。但是,非常好的解決方案謝謝!我將在下次遇到同樣的問題時考慮這一點。 – DocDbg