Странность SQL-транзакций с параллельными процессами из C # - PullRequest
0 голосов
/ 24 февраля 2010

У нас есть система C #, которая вызывает странность, которую мы не можем понять с помощью SQL (SQL2k5).

Ситуация такова, что у нас есть два отдельных процесса, работающих одновременно и смотрящих на одну и ту же таблицу, причем оба выполняются внутри собственной транзакции в двух разных обслуживаемых компонентах COM + в двух разных кластерах. Оба говорят с Order и OrderItem таблицами SQL. Оба работают на уровне изоляции READ COMMITTED.

Задание 1: загрузка заказа и одного или больше предметов в эти таблицы.

Задание 2: запланированное задание, которое происходит каждые несколько минут выбирая из сказанного таблицы с поиском всех заказов, которые имеют был полностью обработан.

Проблема: Мы обнаружили, что четыре раза за последние восемь месяцев задание 2 реагировало на частично загруженный заказ задания 1 до того, как задание 1 было полностью выполнено (как элемент на заказ не был заполнен, он находится в завершенном состоянии, так что это видно по заданию, так как остальная часть заказа еще не загружена).

По результатам расследования, пока выполняется работа 1, мы не можем выполнить:

выбрать * из заказа

после того, как в него был вставлен заказ. Тем не менее, мы можем сделать:

select * fromOrder o внутреннее объединение OrderItem oi on oi.orderid = o.id

одновременно (почему это так?).

При расследовании, повторяющем те же обстоятельства, мы не можем заставить задание 2 увидеть частично созданный заказ из задания 1, оно возвращает некоторые строки, но никогда не вставляет порядок, заданный заданием 1. Однако это именно то, что происходит в наша живая среда!

Кто-нибудь знает, почему это происходит?

Ответы [ 2 ]

0 голосов
/ 30 апреля 2012

Проблема в том, что когда вы открываете транзакцию и добавляете несколько строк, эти строки блокируются, пока транзакция не будет зафиксирована.

Когда вы SELECT * выполняете выбор, который включает заблокированные строки, поэтому, прежде чем он позволит ВЫБРАТЬ, вы должны разблокировать их, совершив или откатив транзакцию.

0 голосов
/ 24 февраля 2010

Я бы попытался откатить некоторую работу, выполненную заданием 1, в качестве эксперимента, чтобы подтвердить, что все, что вы считаете включенным в транзакцию, фактически удаляется при откате. Я, как и вы, подозревал бы, что вы никогда не сможете прочитать данные из другой транзакции, которые будут удалены при откате при использовании READ COMMITTED. Тот факт, что вы можете читать строки, предполагает, что некоторые из них могут входить вне контекста транзакции.

Моя следующая мысль - пересмотреть значение READ COMMITTED. Этот уровень изоляции предположительно гарантирует, что данные, которые вы читаете, был зафиксирован одной транзакцией, но не обязательно гарантирует, что они все еще не могут измениться в результате другой. Сравните это с REPEATABLE READ, где все данные остаются заблокированными до конца транзакции, или с SERIALIZABLE, который пытается вести себя так, как будто все транзакции были выполнены последовательно. Я подозреваю, что если вы измените блокировку на SERIALIZABLE (наиболее ограничивающую), эта конкретная проблема не возникнет, но это может быть излишним.

После рассмотрения значения READ COMMITTED по сравнению с другими уровнями изоляции, я подозреваю, что поведение, которое вы видите, является естественным на этом уровне изоляции, потому что вставленные вами строки на самом деле будут строками, которые все еще будут присутствовать на конец сделки. Я думаю, что READ COMMITTED не предназначен для того, чтобы запрос возвращал полный набор строк (что потребовало бы блокировки диапазона, как наложено SERIALIZABLE), но только для того, чтобы отдельные строки, которые вы читаете, были полностью вставлены (так что вы ' не читаю частичную строку). Я могу ошибаться, но, учитывая поведение, которое вы описываете, это мое подозрение. Если вам нужно убедиться, что весь набор строк завершен, я думаю, что вам нужна SERIALIZABLE изоляция.

Какая транзакция должна быть SERIALIZABLE? Очевидно, что если они оба SERIALIZABLE, это должно работать. Но может быть возможно сделать только один из них Сериализуемым и все же получить правильное поведение. Мои умственные способности на данный момент не соответствуют задаче определения того, что действительно должно быть СЕРИАЛИЗИРУЕМЫМ, но, возможно, некоторые комментарии других прольют дополнительный свет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...