Вопрос

У меня есть простая таблица с первичным ключом. Большинство операций чтения извлекают одну строку по точной цене ключа.

Данные в каждой строке поддерживают некоторые отношения со строками до и после него в ключевом порядке. Поэтому, когда я вставляю новый ряд, мне нужно прочитать 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, эта оператор выбора должен предотвратить вставку новых строк, что изменится результат выбора.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top