Как заблокировать таблицу БД или ряд строк для письма?
-
08-10-2019 - |
Вопрос
У меня есть простая таблица с первичным ключом. Большинство операций чтения извлекают одну строку по точной цене ключа.
Данные в каждой строке поддерживают некоторые отношения со строками до и после него в ключевом порядке. Поэтому, когда я вставляю новый ряд, мне нужно прочитать 2 строки, между которыми он собирается войти, сделать некоторые вычисления, а затем вставить.
Концерн, четко, в том же, что в то же время другая связь может добавить строку с ключом значение в том же интервале. Я покрыт, если это точно такое же значение ключа, поскольку вторая вставка будет не удана, но если значение ключа отличается, но в том же интервале отношения могут быть нарушены.
Раствор, по-видимому, должен заблокировать всю таблицу для записи, когда я решаю добавить новую строку или (если это возможно, что я сомневаюсь) для блокировки интервала ключевых значений. Тем не менее, я бы предпочел, что транзакции только для чтения не будут заблокированы в то время.
Я использую ODBC с libodbc ++ обертка для C ++ В клиентской программе и IBM DB2 Free Edition (хотя выбор БД все еще может изменяться). Это то, о чем я думал:
- Запустите соединение в режиме выделения Auto-Commit и по умолчанию
- Когда необходимо добавить новую строку, установите автоматический коммитируемый режим ложного и изоляции для сериализации
- Прочитайте строки до и после нового значения ключей
- вычислить и вставить новую строку
- совершить
- Вернитесь обратно в режим изоляции Auto-Commit и по умолчанию
Будет ли это сделать работу? Будут ли другие транзакции будут прочитать одновременно? Есть ли другие / лучшие способы сделать это?
Кстати, я не вижу в способе LibODBC ++ I / FA для уточнения транзакции только для чтения. Возможно ли в ODBC?
Редактировать: Спасибо за очень полезные ответы, у меня были проблемы с выбором одного.
Решение
Если ваша база данных находится в сериализуемом режиме, у вас не будет никаких проблем вообще. Учитывая ключ k, чтобы получить предыдущие и следующие клавиши, которые вам необходимо запустить следующие запросы:
select key from keys where key > K order by key limit 1; # M?
select key from keys where key < K order by key desc limit 1; # I?
Вышеуказанные работы в MySQL. Это эквивалентное запрос работает в DB2 (из комментариев):
select key from keys where key = (select min(key) from keys where key > K);
select key from keys where key = (select max(key) from keys where key < K);
Первый запрос устанавливает блокировку диапазона, который предотвращает другие транзакции вставлять ключ больше K и меньше или равных M.
Второй запрос устанавливает блокировку диапазона, который предотвращает другие транзакции вставлять ключ меньше K и больше или равных I.
Уникальный индекс на первичном клавише предотвращает вставление K дважды. Так что вы полностью покрыты.
Это какие транзакции о; Таким образом, вы можете написать свой код, как если бы вся база данных заблокирована.
Примечание. Для этого требуется база данных, которая поддерживает истинную сериализацию. К счастью, DB2 делает. Другие СУБД, которые поддерживают истинную сериализацию: SQLSERVER, а MySQL / InnoDB. СУБД, который не: Oracle, PostgreSQL!
Другие советы
Если ваша база данных и двигатель хранения позволяют, вы должны выдавать SELECT FOR UPDATE
Для обеих строк вы пытаетесь вставить между.
Это будет конфликтовать с любым одновременным SELECT FOR UPDATE
.
Недостатком является то, что замок строк 10
а также 12
(вставить 11
) также предотвратит выбор 8
а также 10
(вставить 9
).
InnoDB
в MySQL
может также разместить next-key
Заблокируйте индекс, это блокировка записи индекса и зазора между следующей записью.
В этом случае вам нужно было бы только выдать SELECT FOR UPDATE
В первом ряду и таким образом вставляйте одновременно подряд до этого.
Тем не менее, это требует заставления индекса и предоставления range
Состояние в индексе, которое может быть или может быть невозможно в зависимости от вашего запроса.
Ваш общий подход правильный. Но вы должны использовать оператор SELECT, который охватывает два ряда и все возможные ряды между ними. Например:
SELECT * FROM MYTABLE WHERE PKCOL BETWEEN 6 AND 10
В системах баз данных с пессимистичной блокировкой и уровнем изоляции транзакции Serializable, эта оператор выбора должен предотвратить вставку новых строк, что изменится результат выбора.