2009-07-23 8 views
7

У меня проблемы с обновлением Oracle. Вызов ExecuteNonQuery вешает бесконечно.Oracle Update Hangs

Код:

using (OracleCommand cmd = new OracleCommand(dbData.SqlCommandStr, conn)) 
{ 
    foreach (string colName in dbData.Values.Keys) 
     cmd.Parameters.Add(colName, dbData.Values[colName]); 

    cmd.CommandTimeout = txTimeout; 
    int nRowsAffected = cmd.ExecuteNonQuery(); 
} 

CommandTimeout создается до 5, и параметры создаются для малых целых значений.

Запрос:

UPDATE "BEN"."TABLE03" SET "COLUMN03"=:1,"COLUMN04"=:2 WHERE COLUMN05 > 0 

Запрос быстро бежит от SQLPLUS, и обычно проходит быстро из моего кода, но каждый раз в то время он висит навсегда.

Я запустил запрос на v $ locked_object, и есть одна запись, ссылающаяся на эту таблицу, но я думаю, что это обновление, которое не выполняется.

Есть две вещи, которые я хотел бы знать: что может привести к зависанию обновления?

Что еще более важно, почему здесь не исключение? Я ожидаю, что вызов будет ждать пять секунд, а затем тайм-аут.

+0

Какую версию Oracle? Можете ли вы запустить этот запрос: «выберите * из v $ version» и скопируйте строку 1. Он должен выглядеть примерно так: «Oracle Database 10g Release 10.2.0.4.0 - Production». Кроме того, это реальная таблица или представление вместо триггеров? Есть ли у него триггеры до/после? –

ответ

5

Когда простое обновление зависает, это часто означает, что вы заблокированы другим сеансом. Oracle не позволит более одной транзакции обновлять строку. До тех пор, пока транзакция не завершит или не откажет свои изменения, она заблокирует строки, которые она обновила/удалила. Это означает, что другим сеансам придется ждать, если они захотят изменить одни и те же строки.

Вы должны ВЫБРАТЬ ... ДЛЯ ОБНОВЛЕНИЯ NOWAIT перед обновлением, если вы не хотите зависать неопределенно.

+0

+1, особенно для спорадических зависаний. – DCookie

0

похоже, что база данных ожидает фиксации/отката, поэтому она блокирует строку. Я хотел бы предложить добавить

int nRowsAffected = cmd.ExecuteNonQuery(); 
cmd.Commit(); 
2

Вы можете увидеть, что событие сеанс ждет на с помощью запроса V $ SESSION_WAIT (после определения SID сессии, вероятно, глядя на V $ SESSION). Если событие похоже на «enqueue», вы ожидаете блокировки, проведенной другим сеансом, что в данном случае похоже на вероятное объяснение.

19

Я натыкаюсь на это из-за ранжирования страницы в результатах поиска.

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

Выполнение обновления SqlPlus решило проблему.

+3

Спасибо, это было очень полезно. Я сделал то же самое ... – stoj

+1

что случилось со мной. как только я выполнил «откат» в SQLPlus, он вернулся. –

+0

спасатель - 4 года спустя! – jasonscript

0

Я часто сталкивался с этой проблемой и не только с запросами обновления (в частности, «INSERT INTO ... SELECT FROM»). Это на Oracle 9i.

Я нашел решение, поэтому решил найти эту связанный SO тему: в строке соединения, установите:

Pooling=False 

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

DATA SOURCE=k19.MYDOMAIN.com/plldb;PERSIST SECURITY INFO=True;Pooling=False;USER ID=IT;Password=SECRET 

Предостережение: Установка Объединивой лжи потребует ваш запроса обеспечить новое соединение каждый раз, когда он запускается. Запросы, которые выполняются очень часто, могут испытывать снижение производительности по сравнению с тем, что у них было бы, если бы ODP.NET был надежным. Однако, учитывая проблему, работа немного медленнее, чем повешение.

4

У меня была аналогичная проблема, вызванная командой Sql, которая не была зафиксирована - я предполагаю, что программа была разбита в середине одного в какой-то момент.

Вот как я исправил мой вопрос:

Сначала откройте Sqlplus и не коммита исправить эту проблему.

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

Вы можете изменить свой код, чтобы что-то вроде этого:

using (OracleTransaction transaction = conn.BeginTransaction()) 
{ 
    using (OracleCommand cmd = new OracleCommand(dbData.SqlCommandStr, conn)) 
    { 
     foreach (string colName in dbData.Values.Keys) 
      cmd.Parameters.Add(colName, dbData.Values[colName]); 

     cmd.CommandTimeout = txTimeout; 

     try 
     { 
      int nRowsAffected = cmd.ExecuteNonQuery(); 
      transaction.Commit(); 
     } 
     catch 
     { 
      transaction.Rollback(); 
     } 
    } 
}