Exceptionfault
Erfahrenes Mitglied
Aber gerne doch ;-)Wie wärs denn mal mit einem "Tutorial" zum Thema locking in Oracle?
Row-Level Locking
Table Level Locking
Select for update
Deadlock
Wie findet man heraus wer welche Tabelle/Zeile gelockt hat und wie sieht man wer auf die Freigabe des Locks wartet...
Locking ist eines der entscheidenden Verfahren um das ACID Prinzip von Transaktionen in Datenbanken zu wahren. ACID steht hierbei für Atomicity, Consistency, Isolation und Durability. Eine Transaktion muss also Isoliert von allen anderen Transaktionen laufen, sie dürfen sich nicht gegenseitig beeinflussen. Ausserdem muss der Zustand der Daten nach einer Transaktion Konsistent sein, es dürfen keine Regeln der Datenbank (Datenlogik) verletzt werden.
Locking dient vor allem zur Isolation der Transaktion und verhindert, dass sich Benutzer durch den gleichzeitigen Zugriff auf die selben Resourcen stören.
Will ein Benutzer also einen Datensatz manipulieren, schliesst danach jedoch seine Transaktion nicht ab, so darf der Datensatz solange von keinem anderen Benutzer geändert werden. Es würde in die Transaktion vom 1. Benutzer eingreifen.
Demo:
Code:
User1:
SQL> conn bert/bert
Connected.
SQL> select * from lock_tes;
FIELD1 FIELD2
---------- ----------
1 Feld1
2 Feld 2
3 Feld 3
SQL> update lock_tes set field1=4 where field1=3;
1 row updated.
-----
User2:
SQL> conn erni/erni
Connected.
SQL> select * from bert.lock_tes for update wait 5;
select * from bert.lock_tes for update wait 5
*
ERROR at line 1:
ORA-30006: resource busy; acquire with WAIT timeout expired
SQL> select * from bert.lock_tes;
FIELD1 FIELD2
---------- ----------
1 Feld1
2 Feld 2
3 Feld 3
SQL> update bert.lock_tes set field2='Test' where field1=1;
1 row updated.
Das ganze nennt man nun Row Level Locking, da der Lock nur auf dem einzelnen Datensatz liegt, man sieht am zweiten Update, dass es mit einem anderen Datensatz problemlos funktioniert.
Das schlimmste was ein Anwendungsentwickler produzieren kann sind sog. Full Table Locks. Das bedeutet jeder Satz der Tabelle ist gesperrt, was schonmal eine komplette Applikation lahm legen kann... Daher Updates möglichst in kleinen Transaktionen und möglichst rasch abschliessen!
Ein Table Level Locking (bzw, Object Level Locking) tritt meistens dann auf, wenn DDL Statements auf das Objekt wirken. Denkbar wäre z.B. das verschieben einer Tabelle in ein anderes Datenfile, der Neuaufbau einen Indizes etc. In diesem Fall ist das komplette Objekt für den Benutzerzugriff gesperrt. Zusätzlich gibt es noch DDL Locks. Diese verhindern z.B. das Droppen einer Tabelle falls gerade eine View erstellt (kompiliert wird) welche auf diese Tabelle zugreift.
Erfahrungsgemäss ist das Lockingverfahren von Oracle sehr sehr gut und alle mir bisher bekannten Probleme rühren von schlechter Entwicklung. Einer der gravierensten Fehler, nämlich ein "unsortierter" Zugriff auf Objekte führt bei stark genutzten Applikationen ständig zu Deadlocks:
Code:
Erni:
SQL> UPDATE bert.lock_tes set field2='Test2' where field1=1;
1 row updated.
Bert:
SQL> update lock_tes set field2='Test3' where field1=2;
1 row updated.
Erni:
SQL> update bert.lock_tes set field2='Testbla' where field1=2;
... Transaktion wartet, wegen Lock von Bert...
Bert:
SQL> update lock_tes set field2='djkfh' where field1=1;
... Transaktion wartet, wegen Lock von Erni...
Erni:
update bert.lock_tes set field2='Testbla' where field1=2
*
ERROR at line 1:
ORA-00060: deadlock detected while waiting for resource
Auf welchem Objekt gerade ein Lock sitzt, und ob und wer gerade darauf wartet, kann man aus mehreren Tabellen im Data Dictionary lesen.
Einen guten Einstieg gibt die Tabelle DBA_BLOCKERS. Sie liefert die SessionID der User, die andere User blockieren. Die SessionID kann man widerum in der v$Session Abfragen und somit den User, den Host und die Applikation ermitteln.
Auch V$SESSION_WAIT ist gut, sie zeigt wartende Benutzer.
DBA_DML_LOCKS zeigt alle DML Locks in der Datenbank. Noch etwas genauer, wenn man z.B. die gelockte Zeile ermitteln will, ist jedoch die View v$Lock, wenn auch etwas kompliziert zu lesen.
Code:
SQL> select * from v$lock where sid in ( select sid from v$session where username <> 'ORACLE');
ADDR KADDR SID TY ID1 ID2 LMODE REQUEST CTIME BLOCK
-------- -------- ---------- -- ---------- ---------- ---------- ---------- ---------- ----------
29E1957C 29E19590 39 TX 327698 298 0 6 852 0
292BC6F4 292BC70C 39 TM 52533 0 3 0 852 0
292BC7A0 292BC7B8 49 TM 52533 0 3 0 1143 0
292D7620 292D773C 49 TX 327698 298 6 0 1143 1
SQL> select sid, username from v$session where sid in (39, 49);
SID USERNAME
---------- ------------------------------
39 ERNI
49 BERT
SQL> SELECT Owner, Object_type, object_name from dba_objects where object_id = 52533
OWNER OBJECT_TYPE OBJECT_NAME
------------------------------ ------------------- --------------------
BERT TABLE LOCK_TES
Eine hübsche Methode den Datensatz zu bekommen:
Code:
Wir nehmen die SID der geblockten Session (siehe v$lock):
SQL> SELECT SID, ROW_WAIT_OBJ#, ROW_WAIT_FILE#, ROW_WAIT_BLOCK#, ROW_WAIT_ROW# FROM V$SESSION WHERE SID = 49;
SID ROW_WAIT_OBJ# ROW_WAIT_FILE# ROW_WAIT_BLOCK# ROW_WAIT_ROW#
---------- ------------- -------------- --------------- -------------
49 52533 4 404 1
... ermitteln den Namen des Objekts (über DBA_OBJECTS) und fragen die Zeile mit der gesuchten ROWID ab:
SQL> SELECT * FROM BERT.LOCK_TES WHERE ROWID = DBMS_ROWID.ROWID_CREATE(1, 52533, 4, 404, 1);
FIELD1 FIELD2
---------- ----------
2 Test3
Tada ;-)
Allgemein kann man sagen, dass Locking ein sehr schwieriges Thema ist. Schon alleine die Theroie über Isolation Levels etc.. würde den Rahmen hier bei weitem sprengen. Dennoch sollte aber jeder Entwickler zumindest das ACID Prinzip verstanden haben und wissen worauf es in seinem verwendeten RDBMS ankommt um es erfolgreich umzusetzen. Ich muss zugeben, dass mir oft auch nie ganz klar wird wann Oracle welchen Lock setzt und was dann noch alles erlaubt wird, in so einem Fall hilft eben einfach nur ausprobieren.
Ums Testen kommt man sowieso nicht drum rum, denn spätestens bei einem Versionswechsel kann sich das Locking Verhalten wieder ändern. Seit Oracle 9 gibt es auch schöne Features wie "ALTER INDEX REBUILD ONLINE". Dies verhindert z.B. ein kompletten Lock des Indizes so dass dieser weiterhin benutzt werden kann, bis er an anderer Stelle komplett neu aufgebaut wurde. (Kann bei sehr großen Tabellen durchaus Sinn machen)
Soviel erstmal zum Thema Locking. Im Moment wüsste ich nicht was ich dazu noch erklären könnte ohne zu tief einzusteigen ?!