2010-07-06 2 views
2

Вот код (с сервера/пароли и т.д. удалены)Почему это обновление блокирует строку в Oracle 10?

public int SetUploadedInESIDatabase(string ID) 
     { 
      using (var oOracleConn = new OracleConnection()) 
      { 
       oOracleConn.ConnectionString = 
        @"Data Source=(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)(HOST=<ip>)(PORT=1521)))(CONNECT_DATA=(SERVER=DEDICATED)(SERVICE_NAME=<dbname>)));User Id=<user>;Password=<password>;"; 
       var cmd = 
        new OracleCommand(
         "UPDATE FOO_ACCESS SET PIMAGE ='-1' WHERE CODE= '" + ID + "'", oOracleConn); 

       oOracleConn.Open(); 



       return cmd.ExecuteNonQuery(); 

      } 
     } 

Эффект этого кода он никогда не получает мимо возвращения заявления. Ошибка не возвращается (даже за одну ночь)

Я не эксперт по базам данных, но наш жесткий диск DBA говорит, что соединение блокировалось (или, возможно, строка ...) он убил соединение блокировки, но все же, когда я запускаю код блокируется.

Я делаю это неправильно (tm) в отношении просьбы Oracle обновить строку?

Я понимаю, что должен использовать параметризованный запрос, но у меня была проблема с этим и нужны простые вещи! Если я скопирую встроенную команду из cmd. с отладчиком и запускать его с помощью SQL Developer, тогда он работает (хотя иногда он также блокируется)

Я могу выбрать из базы данных по желанию.

Я не уверен, что это нормальная вещь или что-то общее с нашей средой, поэтому любая помощь с радостью принимается!

+0

Ого, это действительно то, что строка соединения Oracle похоже на C#? Это фактически делает строки Java-соединения для Oracle выглядят красивыми в сравнении! – Powerlord

+0

@ R.Bemrose: Это только то, что выглядит строка подключения, если вы не используете файл Oracle TNSNAMES.ORA для предоставления дружественных имен для серверов. В противном случае использование TNSNAMES выглядит намного приятнее: 'Data Source = ServerName; Идентификатор пользователя = пользователь; Пароль = pw'. – LBushkin

+0

@R. Bemrose: Oracle поддерживает различные форматы строк подключения. Http://www.connectionstrings.com/oracle#p12 – devio

ответ

2

Объединение @ Тони и @Panagiotis ответы, а также расширение:

Где вы фиксируете UPDATE сделано в этом коде? Вы уверены, что это делается?

Может быть, это ваш сценарий:

  1. Вы оформить выше UPDATE, но никогда не совершал.
  2. Вы не видите изменений, поэтому повторите попытку. Теперь он висит.

Строки, затронутые UPDATE, блокируются от дальнейших обновлений до тех пор, пока они не будут завершены или не откатны. Если вы никогда явно не совершаете или откатываете, последующие обновления будут зависать.

Если вы хотите, чтобы избежать повесить в вашем коде, а затем выполнить

SELECT... FOR UPDATE NOWAIT; 

, прежде чем сделать UPDATE. Если запись заблокирована, выбор вернет ошибку, которую вы можете поймать и обработать.

Попросите DBA попробовать этот запрос (Tom Kyte благодариться):

select 
     (select username from v$session where sid=a.sid) blocker, 
     a.sid, 
     ' is blocking ', 
     (select username from v$session where sid=b.sid) blockee, 
      b.sid 
    from v$lock a join v$lock b on (a.id1 = b.id1 and a.id2 = b.id2) 
where a.block = 1 
    and b.request > 0; 

Чтобы увидеть все поставленные в очередь на блоки на сеансах.

+0

Спасибо за это. Я нашел проблему (см. Мой «ответ» в другом месте), однако этот способ сделать ошибку, если он не может получить строку для обновления, полезен, поэтому вы получаете файл cookie :) – Loofer

1
  • Узнайте, что именно заблокирован (таблица, строки и т.д.)

  • Вы можете выполнить оператор из SQLPLUS или SQLDeveloper используя же учетные данные?

  • Подключаются ли какие-либо триггеры к таблице FOO_ACCESS?

+0

Спасибо. Я могу запустить запрос из sqldeveloper, и он * иногда * работает ... в коде он * никогда * работает. Я получу полезный DBA для остальных :) – Loofer

1

Вы уверены, что параметр studentID действительно просто ID? Что, если это был malformed bit of SQL that someone tries to inject?

Вполне возможно, что som unsanitized input сделал свой путь в studentID - и заставляет ваш запрос делать что-то другое, кроме того, что вы ожидаете.

Например, если studentID = "'; DROP ALL TABLES; --" вы можете иметь проблемы ...

Использование строки concatentation в качестве средства для создания SQL заявления является небезопасным - и один, что совершенно ненужным. В SQL-командах довольно просто использовать параметры в .NET, что делает SQL менее восприимчивым к инъекционным атакам, а также улучшает их производительность (уменьшая необходимость в синтаксическом анализе операторов).

Вот пример, который использует параметры:

var cmd = new OracleCommand( 
     "UPDATE FOO_ACCESS SET PIMAGE = '-1' WHERE CODE = :code", oracleConn); 
cmd.Parametes.Add(":code", studentID); 

cmd.ExecuteNonQuery(); 

Кроме того, вы можете выяснить, что вызывает ваш запрос для выполнения плохо с помощью таблицы V $ XXX в Oracle, чтобы выяснить, что происходит. Если вы считаете, что у вас есть блокировка, вы можете запросить таблицу v$lock, чтобы увидеть, какие таблицы заблокированы с помощью этих сеансов.

+0

Я сейчас в разработке, поэтому никакие дикие типы не могут попробовать и получить меня. Я, конечно, только позволю параметризовать вещи в дикой природе! (как я сказал в своем вопросе :) У меня нет прилавков, чтобы увидеть таблицу блокировки v $, поэтому вернемся к dba! – Loofer

+0

Теперь я запрограммировал свой запрос: D Это было так просто, как вы говорите, однако это делает отладку немного сложнее в Visual Studio, поскольку VS, похоже, не создает финальную команду, где вы можете ее видеть, поэтому я не мог копировать и вставьте созданную команду sql в другую программу для тестирования. – Loofer

1

Если один сеанс выдает это обновление и не фиксирует или откатывается, строка блокируется этим сеансом до тех пор, пока он не выполнит (завершение или откат). Может ли это быть с тобой?

+0

Это звучит скорее всего, но почему он не совершает или не откатывается, если UPDATE терпит неудачу ... могу ли я намекнуть на это, что я хотел бы, чтобы он переставал пытаться в какой-то момент? – Loofer

1

Вы пытались открыть соединение перед созданием объекта команды?

+0

Это, кажется, не имеет никакого эффекта. Спасибо, хотя :) – Loofer

1

Oracle будет блокировать строку, если несколько авторов попытаются коснуться ее в одно и то же время. Является ли какой-либо другой код попыткой изменить строку или таблицу одновременно? Возможно, вы выполнили инструкцию SELECT FOR UPDATE в другом открытом соединении?

+0

UPDATE - единственный SQL, который я запускаю ... Я не знаю о SELECT FOR UPDATE ... это то, что я ДОЛЖЕН делать? – Loofer

1

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

using(OracleTransaction transaction = oOracleConn.BeginTransaction(IsolationLevel.RepeatableRead) 
{ 

cmd.Transaction = transaction 

return cmd.ExecuteNonQuery(); 
} 
+0

No ... is RepeatableRead, что я хочу? Глядя на перечисление, возможно .Chaos: D – Loofer

1

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

т.е. вместо:

using (..snip...) { 

    return cmd.ExecuteNonQuery(); 
} 

попробовать

int rv; 
using() { 

    rv = cmd.ExecuteNonQuery(); 
} 
return rv; 
+0

Он никогда не попадает в оператор возврата, оставаясь застрявшим в стадии cmd.ExecuteNonQuery(). – Loofer

+0

Что произойдет, если вы замените sql на простой select - i.e выберите count (*) из foo_access? Есть ли причина, по которой вы не используете tnsnames.ora для разрешения соединения? – chris

+0

Выберите отработанные часы. Я не использую tnsnames.ora, поскольку я ничего не знаю об Oracle, и dba ничего не знает о программировании, и я делаю все, что работает или похоже работает: O – Loofer

0

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

Я считаю, что SQL Developer создавал блокировку в какой-то момент, а затем, когда я запускал свое веб-приложение для обновления той же строки, он блокировался. В моем разочаровании и невежестве я принудительно закрыл SQL Developer, оставив блокировку, застрявшую в базе данных, и я не смог ее очистить без суперсовместимости DBA.

Теперь, когда блокировка была очищена и закрыта всеми работающими копиями SQL-разработчика, он полностью очистил код, когда я впервые разместил его сейчас. (Уф!)

Спасибо за вашу помощь, особенно идея ИЗБРАННЫХ UPDATE, чтобы увидеть, если мое обновление будет отказано, прежде чем я выпустить его :)

+0

Когда вы делаете обновление в sqldeveloper, вам нужно явно указать совершить транзакцию. Есть параметр автоматической фиксации, но если вы включите это, я обещаю вам, что когда-нибудь вы пожалеете об этом. – chris

Смежные вопросы