Базы данных Oracle - статьи

         

Процедура


Смоделируем следующую ситуацию. Создадим процедуру p1 с единственной командой, которая будет обновлять нужную нам строку таблицы t1 в зависимости от входных параметров:

SQL> CREATE PROCEDURE p1(v1 in integer, v2 in VARCHAR2)   2> AS   3> BEGIN   4>   UPDATE t1 SET c2 = v2 WHERE c1 = v1;   5> END;   Процедура изменена

Образуем два сеанса. В первом сеансе изменим первую строку:

ZH@XE(31)> EXECUTE p1(1, 'Строка1');   PL/SQL procedure successfully completed

Во втором сеансе изменим вторую строку:

ZH@XE(23)> EXECUTE p1(2, 'Строка2');   PL/SQL procedure successfully completed

Вернёмся в первый сеанс и изменим вторую строку:

ZH@XE(31)> EXECUTE p1(2, 'Строка2');

Ожидание…

Возникло ожидание. И это естественно, ведь мы следуем по пути первого сценария  образования взаимной блокировки. Единственное отличие для нашего случая, это только то, что SQL-команды здесь спрятаны в PL/SQL процедуре. Поэтому, если дальше следовать сценарию, выполнение следующей команды, изменяющей первую строку, должно привести к взаимному блокированию:

ZH@XE(23)> EXECUTE p1(1, 'Строка1');

Ожидание…

Так и есть, в первом сеансе происходит ошибка:

ZH@XE(31)> EXECUTE p1(2, 'Строка2');   BEGIN * Ошибка в строке 1: ORA-00060: deadlock detected while waiting for resource ORA-06512: at "ZH.P1", line 4 ORA-06512: at line 2

Возникшая взаимная блокировка подобна самому первому случаю, который мы рассматривали в самом начале статьи. Первый сеанс установил TX-блокировку в монопольном режиме на первую строку и  ожидает установки такой же блокировки  на вторую строку. Второй сеанс, наоборот, установил TX-блокировку в монопольном режиме на вторую строку и ожидает установки такой же на первую строку. Всё, как при обычном сценарии с SQL-командами.

Рассмотрим теперь содержимое трассировочного файла взаимной блокировки. Есть ли здесь какие-либо изменения?   Первая секция содержит отменённый в результате ошибки оператор первого сеанса:

Current SQL statement for this session: UPDATE T1 SET C2 = :B2 WHERE C1 = :B1


Как видим, это команда UPDATE, содержащаяся в нашей процедуре p1. Правда, это мы знаем, что данная SQL-команда принадлежит этой процедуре. Но обычно бывает трудно  идентифицировать PL/SQL-объект, которому принадлежит данный курсор. И в этом нам может помочь новый блок трассировочного файла, содержащий информацию стека  вызовов PL/SQL. Он располагается сразу после первой секции вслед за словами   PL/SQL Call Stack:

----- PL/SQL Call Stack -----   object      line  object   handle    number  name 29CDE8E4         4  procedure ZH.P1 2670C20C         2  anonymous block

В нашем случае мы сразу можем определить, что отменённая команда принадлежит процедуре ZH.P1. Но иногда здесь может оказаться сразу несколько объектов, и в этом случае установить, кому из них принадлежит  отменённый SQL-оператор, бывает трудно.   

Остальные секции трассировочного файла содержат обычную для такого сценария информацию, поэтому мы не будем подробно её разбирать:

Deadlock graph:                        ---------Blocker(s)--------  ---------Waiter(s)--------- Resource Name          process session holds waits  process session holds waits TX-00070008-000000e1        21      31     X             25      23           X TX-0009002c-000000d9        25      23     X             21      31           X

Rows waited on: Session 23: obj - rowid = 0000360E - AAADYOAAEAAAAGfAAA   (dictionary objn - 13838, file - 4, block - 415, slot - 0) Session 31: obj - rowid = 0000360E - AAADYOAAEAAAAGfAAB   (dictionary objn - 13838, file - 4, block - 415, slot - 1)

Итак, как мы убедились, взаимная блокировка при выполнении процедур ничем кардинально не отличается от сценариев с отдельными SQL-командами. Разве только в трассировочном файле появилась новая секция о стеке  вызовов PL/SQL. Правда, в процессе моделирования ситуации мы забыли упомянуть об одной важной вещи.  Если при возникновении взаимного блокирования с SQL-командами Oracle для нормализации ситуации отменяет одну из SQL-команд, то что он отменит в нашем случае взаимной блокировки с  PL/SQL объектами?


Содержание раздела