Myślę, że najlepszym sposobem, aby obsłużyć to byłoby użyć SELECT ... FOR UPDATE wzorca opisanego tutaj: http://dev.mysql.com/doc/refman/5.0/en/innodb-locking-reads.html
Dla porównania:
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.
Tak więc w Twoim przypadku, należy zastąpić
LOCK TABLES AlarmCount WRITE, AlarmMembership READ;
UPDATE AlarmCount SET num = num - 1
WHERE RuleId = OLD.RuleId AND
MemberId = 0 AND
IsResolved = OLD.IsResolved;
z czymś
SELECT num FROM AlarmCount WHERE RuleId = OLD.RuleId AND
MemberId = 0 AND
IsResolved = OLD.IsResolved FOR UPDATE;
UPDATE AlarmCount SET num = num - 1;
mówię "coś takiego", ponieważ to nie jest do końca jasne, co do mnie i OLD.RuleId OLD.IsResolved odwołuje się. Warto również zauważyć, ze http://dev.mysql.com/doc/refman/5.0/en/innodb-locking-reads.html jest:
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.
Innymi słowy, prawdopodobnie można zoptymalizować ten wzór dalej tylko dostępu tabelę raz ... ale znowu tam kilka szczegółów na temat swojego schematu, że nie podążają za mną i nie jestem pewien, czy mógłbym podać rzeczywiste oświadczenie, którego potrzebujesz. Myślę, że jeśli spojrzysz WYBIERZ ... NA AKTUALIZACJĘ, zobaczysz, do czego ten wzór się sprowadza i co musisz zrobić, aby działało to w twoim środowisku.
Muszę również wspomnieć, że istnieje pewne środowisko przechowywania i poziomy izolacji transakcji, które warto wziąć pod uwagę. Jest bardzo, bardzo dobra dyskusja na temat SO na ten temat tutaj: When to use SELECT ... FOR UPDATE?
Mam nadzieję, że to pomoże!
Skończyło się na zablokowaniu kodu wywołującego, więc zapobieganie potencjalnym konfliktom. Ale, bardzo ładne rozwiązanie dzięki! Rozważę to na następny raz, mam ten sam problem. – DocDbg