Какой уровень изоляции следует использовать для следующей транзакции вставки, если нет? - PullRequest
1 голос
/ 21 мая 2010

Я написал программу linq-to-sql, которая, по сути, выполняет задачу ETL, и я заметил много мест, где распараллеливание улучшит свою производительность. Однако я обеспокоен предотвращением нарушений ограничений уникальности, когда два потока выполняют следующую задачу (код psuedo).

Record CreateRecord(string recordText)
{
    using (MyDataContext database = GetDatabase())
    {
        Record existingRecord = database.MyTable.FirstOrDefault(record.KeyPredicate());
        if(existingRecord == null)
        {
            existingRecord = CreateRecord(recordText);
            database.MyTable.InsertOnSubmit(existingRecord);
        }

        database.SubmitChanges();
        return existingRecord;
    }
}

Как правило, этот код выполняет оператор SELECT для проверки существования записи, а затем оператор INSERT, если запись не существует. Он заключен в неявную транзакцию.

Когда два потока запускают этот код для одного и того же экземпляра recordText, я хочу запретить им одновременно определить, что запись не существует, тем самым оба пытаются создать одну и ту же запись. Уровень изоляции и явная транзакция будут работать хорошо, за исключением того, что я не уверен, какой уровень изоляции мне следует использовать - Serializable должен работать, но кажется слишком строгим. Есть ли лучший выбор?

1 Ответ

1 голос
/ 21 мая 2010

Я использую SQL, аналогичный показанному ниже, чтобы избежать подобных ситуаций. UPDLOCK указывает, что блокировки обновления следует снимать и удерживать до завершения транзакции, а HOLDLOCK эквивалентно SERIALIZABLE. SERIALIZABLE делает общие блокировки более строгими, удерживая их до завершения транзакции, вместо того чтобы снимать общую блокировку, как только требуемая таблица или страница данных больше не нужны, независимо от того, была ли транзакция завершена или нет. Сканирование выполняется с той же семантикой, что и транзакция, выполняемая на уровне изоляции SERIALIZABLE. HOLDLOCK применяется только к таблице или представлению, для которых оно указано, и только для продолжительности транзакции, определенной оператором, в котором он используется. HOLDLOCK нельзя использовать в операторе SELECT, который включает FOR BROWSE опция.

declare @LocationID          int
declare @LocationName        nvarchar (50)

/* fill in LocationID and LocationName appropriately */

INSERT dbo.Location
(LocationID, LocationName)
SELECT @LocationID, @LocationName
WHERE NOT EXISTS (
   SELECT L.*
   FROM dbo.Location L WITH (UPDLOCK, HOLDLOCK)
   WHERE L.LocationID = @LocationID)

Согласно ответу на на этот вопрос , Serializable, похоже, и есть путь.

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