2015-05-11 3 views
1

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

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

Возможно ли, что я могу определить эту ситуацию? Возможно обновление-служба может отправить заявление так:

UPDATE person 
    SET email_address = '[email protected]' WHERE person_id='1234567' 
ON LOCKED ERROR; 

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

Или я могу настроить сервер oracle для отправки кода ошибки через определенное время, если блокировка на строке не заканчивается?

Спасибо за помощь.

+1

Вы описываете блокировку, а не тупик. Первое незафиксированное обновление блокирует второе, потому что строка заблокирована. –

+0

Читатели не блокируют писателей, и авторы не блокируют читателей. –

+0

Не только это не тупик, это страшный дизайн, чтобы оставить транзакции открытыми для людей, чтобы «забыть совершить». Если вы не можете исправить это, вы можете использовать предложение SELECT FOR UPDATE WAIT, чтобы выйти рано. – LoztInSpace

ответ

2

Вы могли бы делайте это в два этапа; запрос таблицы с FOR UPDATE NOWAIT, который будет сгенерировано исключение, если строка уже заблокирована, а затем сделать обновление (и фиксации), если это не ошибка:

SELECT * FROM person WHERE person_id = 1234567 FOR UPDATE NOWAIT; 
UPDATE person SET email_address = '[email protected]' WHERE person_id='1234567'; 

Если вы сделаете это из двух сессий, без совершение, то второе для запуска выберите увидит:

ORA-00054: resource busy and acquire with NOWAIT specified or timeout expired

Вы также можете иметь тайм-аут с WAIT <time>:

SELECT * FROM person WHERE person_id = 1234567 FOR UPDATE WAIT 3; 
UPDATE person SET email_address = '[email protected]' WHERE person_id='1234567'; 

в этом случае второй ч Мюллер получит сообщение об ошибке, если первые не совершило/откат в 3 секунде:

ORA-30006: resource busy; acquire with WAIT timeout expired

Если вы вызываете это через JDBC или OCI и т.д., вам может потребоваться иметь отдельные обратные вызовы, на одном сеансе и с первым вызовом, обрабатывающим исключение, если оно выбрано.

+0

Привет, Алекс, это именно то, что мне нужно. Большое спасибо. Приветствие Goetz – Goetz423

3

a person updates a row and forgets the commit. later the update-service always wants to update this row and the service hangs, until the commit will be made or the session will be closed

В идеале читатели не блокируют писателей, а писатели не блокируют читателей.

Что вы описываете не a DEADLOCK сценарий. Когда сеанс выполняет обновление, он получает эксклюзивную блокировку на уровне строк и другую сессию, пытающуюся обновить эти строки, нужно дождаться, когда блокировка будет выпущена COMMIT/ROLLBACK.

Тупик случается, когда две или более сеансов ждут друг друга для блокировки.

Or can i configure the oracle server to send an error code after a defined time, if the lock on a row does not finish?

Для проверки блокировки сеанса и ждать класса, вы можете запросить V $ SESSION вид:

select sid, 
     status, 
     program, 
     sql_id, 
     state, 
     wait_class, 
     blocking_session_status, 
     event 
from v$session; 

Когда дело доходит до тупиков, Oracle обнаруживает тупиковый автоматически, бросает ORA -00060: обнаружен тупик, ожидающий ресурса, и откатывает одну из транзакций, вовлеченных в тупик, которые Oracle решил в качестве жертвы. Предыдущие успешные транзакции не откатываются. Даже после ошибки тупика, если вы совершили фиксацию, будет выполнена предыдущая успешная транзакция. В это время транзакция другого сеанса также будет успешной, и вы можете выполнить фиксацию. Нет ничего, что вам нужно явно здесь делать. Тупики автоматически очищаются - вам не нужно их очищать.

См аналогичный вопрос, который я ответил здесь https://stackoverflow.com/a/28455397/3989608

Для детальной демонстрации и примеры тупиков см Understanding Oracle Deadlock

Если вы используете FOR UPDATE NOWAIT, то Oracle не позволит вам обновить эти строки и бросить следующее сообщение об ошибке:

ORA-00054: resource busy and acquire with NOWAIT specified or timeout expired 

Например,

Сессия 1:

SQL> SELECT empno, deptno 
    2 FROM emp WHERE 
    3 deptno = 10 
    4 FOR UPDATE NOWAIT; 

    EMPNO  DEPTNO 
---------- ---------- 
     7782   10 
     7839   10 
     7934   10 

SQL> 

Сессия 2:

SQL> SELECT empno, deptno 
    2 FROM emp WHERE 
    3 deptno in (10, 20) 
    4 FOR UPDATE NOWAIT; 
    FROM emp WHERE 
     * 
ERROR at line 2: 
ORA-00054: resource busy and acquire with NOWAIT specified or timeout expired 

Переход на шаг дальше, если вы хотите избежать обновления строки, которые уже заблокированы, вы можете использовать ДЛЯ ОБНОВЛЕНИЯ ПРОПУСКА ЗАБЛОКИРОВАТЬ, чтобы избежать других сеансов для извлечения строк для обновления, которые уже заблокированы.

Например,

Сессия 1:

SQL> SELECT empno, deptno 
    2 FROM emp WHERE 
    3 deptno = 10 
    4 FOR UPDATE NOWAIT; 

    EMPNO  DEPTNO 
---------- ---------- 
     7782   10 
     7839   10 
     7934   10 

SQL> 

Сессия 2:

SQL> SELECT empno, deptno 
    2 FROM emp WHERE 
    3 deptno in (10, 20) 
    4 FOR UPDATE NOWAIT; 
    FROM emp WHERE 
     * 
ERROR at line 2: 
ORA-00054: resource busy and acquire with NOWAIT specified or timeout expired 

Теперь давайте пропустить строки которые заблокированные сессии 1.

SQL> SELECT empno, deptno 
    2 FROM emp WHERE 
    3 deptno IN (10, 20) 
    4 FOR UPDATE SKIP LOCKED; 

    EMPNO  DEPTNO 
---------- ---------- 
     7369   20 
     7566   20 
     7788   20 
     7876   20 
     7902   20 

SQL> 

Так, отдел = 10 были заблокированы сессии 1, а затем отдел = 20 блокированы сессии 2.

Смотрите этот же вопрос о избежать обновления на уже заблокированные строки Oracle deadlock keeps repeating on the same record