Обновление столбца XML и блокировка на сервере SQL - PullRequest
2 голосов
/ 09 ноября 2009

У меня есть несколько услуг windwos. Они получают XML-столбец от Sql-сервера и обрабатывают его.

Сервис A - получает XML
Сервис B - получает XML
Сервис A - Обновляет XML (он будет потерян)
Сервис B - Обновления XML

Я должен заблокировать строку и использую следующий код:

SqlCommand cmdUpdate = new SqlCommand();
            cmdUpdate.CommandText = "select MyXML from MyTable with(holdlock,rowlock) where id=@id";
            cmdUpdate.Parameters.AddWithValue("@id", id);

        using (SqlConnection conn = Helper.GetConnection())
        {
            cmdUpdate.Connection = conn;
            SqlTransaction ts = conn.BeginTransaction();
            cmdUpdate.Transaction = ts;
            XElement elem = XElement.Parse(cmdUpdate.ExecuteScalar().ToString());
            UpdateXElement(elem);
            cmdUpdate.Parameters.Clear();
            cmdUpdate.CommandText = "update MyTable set MyXML=@xml where id=@id";
            cmdUpdate.Parameters.AddWithValue("@id", id);
            cmdUpdate.Parameters.AddWithValue("@xml", elem.ToString());

            cmdUpdate.ExecuteNonQuery();
            ts.Commit();
        }
    }`

затем возникает тупик.

У вас есть идея получше, чтобы решить эту проблему?

Спасибо

1 Ответ

0 голосов
/ 09 ноября 2009

Сценарий, который вы описываете, не является тупиком. Другими словами, это утверждение о блокировке:

  1. Сервис A - получает XML - Service A locks XML
  2. Сервис B - получает XML - Services B places lock request which waits for service A to release the lock
  3. Сервис A - Обновляет XML (он будет потерян) - Service A should commit or rollback the transaction to release the lock.
  4. Сервис B - Обновление XML - Service B acquires the lock on the XML and updates it

Service B будет заморожен между шагами 2 и 3.

Это означает, что вы должны выполнить эти шаги как можно быстрее.

Обновление:

Вы используете HOLDLOCK для блокировки строки в транзакции.

HOLDLOCK устанавливает общую блокировку, которая совместима с другой общей блокировкой, но не с блокировкой обновления, установленной UPDATE.

Вот что происходит:

  1. Service A устанавливает общую блокировку на row 1
    • Service B устанавливает общую блокировку на row 1
    • Service A пытается установить блокировку обновления на row 1, которая не совместима с общей блокировкой, установленной Service B на шаге 2. Service A входит в состояние ожидания (все еще удерживая общую блокировку, установленную на шаге 1).
    • Service B пытается установить блокировку обновления на row 1, которая не совместима с общей блокировкой, установленной Service A на шаге 1. Service B переходит в состояние ожидания. ТУПИК .

Нет смысла размещать общую блокировку в предложении SELECT здесь. Вместо этого вы должны поместить UPDLOCK в предложение SELECT. Это сделает блокировки транзакций полностью несовместимыми, и любая транзакция должна будет ждать завершения других транзакций, прежде чем получать какие-либо блокировки.

В этом сценарии тупики невозможны.

...