1. Start
  2. Unternehmen
  3. Blog
  4. Lock-Free Reservations - Sperrfreie Reservierungen

Lock-Free Reservations - Sperrfreie Reservierungen

Die Oracle Datenbank 26ai bringt einige neue Konzepte für Transaktionen mit. Eines dieser Konzepte, die Sperrfreien Reservierungen (engl. Lock-Free Reservations), wird in diesem Blogbeitrag vorgestellt. Sperrfreie Reservierungen können bei Spalten vom Typ NUMBER verwendet werden und eignen sich besonders dann, wenn es für den Wert der Spalte eine feste Grenze gibt, beispielsweise bei Kontingenten oder Kapazitäten.
Bei der Verwendung von Sperrfreien Reservierungen können mehrere Sessions gleichzeitig die entsprechende Spalte aktualisieren, ohne sich zu blockieren oder die Integrität der Daten zu verletzen.
 

Funktionsweise am Beispiel eines Kinosaals

Zur Veranschaulichung des Beispiels wird ein Kinosaal mit der Raumkapazität 100 verwendet.

 

kino> CREATE TABLE programm
  ( id         NUMBER PRIMARY KEY,
    film       VARCHAR2(30),
    kapazitaet  NUMBER(3) RESERVABLE CHECK (kapazitaet >= 0),
    saal       NUMBER,
    filmstart  DATE);
    
Table PROGRAMM created.

kino> INSERT INTO programm
VALUES (1, 'Forrest Gump',100,1,'12-OCT-1994');

1 row inserted.

kino> COMMIT;

Commit complete.

 

Für die Verwendung von Sperrfreien Reservierungen muss die Tabelle einen Primärschlüssel enthalten. Im Beispiel wird die Spalte kapazitaet mit dem Schlüsselwort RESERVABLE für Sperrfreie Reservierungen gekennzeichnet. Weiterhin wird auch ein Check-Constraint für diese Spalte definiert, das dafür sorgt, dass nicht mehr Karten gebucht werden als vorhanden sind.
 

Aktualisieren der Spalte

Damit mehrere Sessions gleichzeitig Änderungen an der Spalte kapazitaet durchführen können, dürfen nur relative Änderungen gemacht werden, d.h. der aktuelle Wert darf nur um einen angegebenen Wert vergrößert oder verkleinert werden.

Der Vorteil dieser Einschränkung ist, dass die Reihenfolge, in der zwei Aktualisierungen angewendet werden, keinen Einfluss auf das Endergebnis haben. Wäre es hingegen erlaubt, den Wert der Spalte direkt anzugeben, würde sich das Endergebnis im Allgemeinen ändern, wenn die Reihenfolge von zwei Aktualisierungen getauscht wird. Dadurch ist es für die Datenbank mit sehr geringem Aufwand möglich, die Folgen noch offener Transaktionen abzuschätzen.

Im Beispiel beginnt nun eine Transaktion, bei der 20 Karten verkauft werden.

 

kino> UPDATE programm
SET kapazitaet = kapazitaet - 20
WHERE id = 1;

1 row updated.

kino> SELECT *
FROM programm;

        ID FILM                           KAPAZITAET       SAAL FILMSTART
---------- ------------------------------ ---------- ---------- ---------
         1 Forrest Gump                          100          1 12-OCT-94

 

Im Gegensatz zu klassischen Transaktionen ist die Änderung in der eigenen Session noch nicht sichtbar, sondern wird erst bei einem Commit angewendet und damit sichtbar. Jedoch werden alle Änderungen der laufenden Transaktion in einer internen Tabelle gespeichert. Der Name der internen Tabelle enthält die Object_id der zugehörigen Tabelle.

 

kino> col object_name format a15
SELECT object_name, object_id
FROM all_objects
WHERE object_name = 'PROGRAMM';

OBJECT_NAME      OBJECT_ID
--------------- ----------
PROGRAMM             87474

kino> col "ora_saga_id$" format a15
col kapazitaet_op format a15
SELECT *
FROM SYS_RESERVJRNL_87474;

ORA_SAGA_ID$    ORA_TXN_ID$      ORA_STATUS$ ORA_ST         ID KAPAZITAET_OP   KAPAZITAET_RESERVED
--------------- ---------------- ----------- ------ ---------- --------------- -------------------
                05000100BF1C0000 ACTIVE      UPDATE          1 -                                20

 

Wichtig sind hier insbesondere die letzten beiden Spalten, in denen die Operation (hier Subtraktion) und der Änderungswert gespeichert werden. Nach einem Commit werden die Einträge wieder aus der internen Tabelle entfernt und die Änderungen an der Tabelle programm sind für alle Benutzer sichtbar.

 

kino> COMMIT;

Commit complete.

kino> SELECT *
FROM programm;

        ID FILM                           KAPAZITAET       SAAL FILMSTART
---------- ------------------------------ ---------- ---------- ---------
         1 Forrest Gump                           80          1 12-OCT-94
        
kino> SELECT *
FROM SYS_RESERVJRNL_87474;

no rows selected

 


Gleichzeitige Aktualisierung mehrerer Sessions

Interessant ist natürlich der gleichzeitige Zugriff mehrerer Sessions auf die Tabelle. Im vorliegenden Fall kann dies beispielsweise durch einen Online-Kartenverkauf erfolgen.
Damit ein anderer Nutzer die Spalte kapazitaet bearbeiten kann, benötigt er nicht nur die entsprechenden Rechte an der Tabelle programm, sondern auch an der zugehörigen internen Tabelle SYS_RESERVJRNL_87474.

 

kino> GRANT SELECT, UPDATE ON programm TO online;

Grant succeeded.

kino> GRANT SELECT, INSERT, UPDATE, DELETE ON SYS_RESERVJRNL_87474 TO online;

Grant succeeded.

 

 

Bei kommenden Aktualisierungen der Spalte kapazitaet wird dieselbe interne Tabelle weiterverwendet.

 

kino> UPDATE programm
SET kapazitaet = kapazitaet - 25
WHERE id = 1;

1 row updated.

kino> SELECT *
FROM SYS_RESERVJRNL_87474;

ORA_SAGA_ID$    ORA_TXN_ID$      ORA_STATUS$ ORA_ST         ID KAPAZITAET_OP   KAPAZITAET_RESERVED
--------------- ---------------- ----------- ------ ---------- --------------- -------------------
                0A0014007D0F0000 ACTIVE      UPDATE          1 -                                25

 

Obwohl die Transaktion noch läuft, kann eine weitere Session ebenfalls eine Aktualisierung vornehmen:

 

online> SELECT *
FROM kino.programm;

        ID FILM                           KAPAZITAET       SAAL FILMSTART
---------- ------------------------------ ---------- ---------- ---------
         1 Forrest Gump                           80          1 12-OCT-94

online> UPDATE kino.programm
SET kapazitaet = kapazitaet - 30
WHERE id = 1;

1 row updated.

 

Bei jeder Aktualisierung wird im Hintergrund geprüft, ob die Aktualisierung das Check-Constraint verletzen könnte. Dabei werden auch offene Transaktionen anderer Sessions berücksichtigt.
Die offenen Änderungen aller Sessions werden alle in derselben Tabelle gespeichert, allerdings sieht jeder Nutzer bei der Abfrage nur seine eigenen Änderungen.

 

online> col "ora_saga_id$" format a15
col Kapazitaet_op format a15
SELECT *
FROM kino.SYS_RESERVJRNL_87474;

ORA_SAGA_ID$    ORA_TXN_ID$      ORA_STATUS$ ORA_ST         ID KAPAZITAET_OP   KAPAZITAET_RESERVED
--------------- ---------------- ----------- ------ ---------- --------------- -------------------
                06001B0030140000 ACTIVE      UPDATE          1 -                                30

 

Die tatsächlichen Aktualisierungen werden erst bei einem Commit durchgeführt.
Obwohl das Commit ausschließlich Datensätze aus der Tabelle kino.SYS_RESERVJRNL_87474 entfernt, benötigt der Benutzer online hierfür nicht nur das DELETE-, sondern das UPDATE-Privileg für diese Tabelle.

 

online> COMMIT;

Commit complete.

online> SELECT *
FROM kino.programm;

        ID FILM                           KAPAZITAET       SAAL FILMSTART
---------- ------------------------------ ---------- ---------- ---------
         1 Forrest Gump                           50          1 12-OCT-94

 

Obwohl der Benutzer online seine 30 Plätze erst reserviert hat, nachdem der Benutzer kino bereits 25 Plätze reserviert hatte, wird seine Änderung zuerst angewendet. Das liegt daran, dass die Aktualisierung erst bei einem Commit tatsächlich angewendet wird und der Benutzer online seine Änderungen zuerst committet hat. Die 25 Plätze des Benutzers kino bleiben weiterhin reserviert, bis sie durch ein Commit bestätigt werden.

 

kino> COMMIT;

Commit complete.

kino> SELECT *
FROM programm;

        ID FILM                           KAPAZITAET       SAAL FILMSTART
---------- ------------------------------ ---------- ---------- ---------
         1 Forrest Gump                           25          1 12-OCT-94

 


Verletzung des Check-Constraints

Wenn eine Aktualisierung das Check-Constraint verletzten könnte, verhindert die Datenbank das entsprechende UPDATE.

 

kino> UPDATE programm
SET kapazitaet = kapazitaet - 20
WHERE id = 1;

1 row updated.

 

 

online> SELECT *
FROM kino.programm;

        ID FILM                           KAPAZITAET       SAAL FILMSTART
---------- ------------------------------ ---------- ---------- ---------
         1 Forrest Gump                           25          1 12-OCT-94

 

Laut Tabelle sind noch 25 Plätze vorhanden. Da aber durch das letzte Update des Benutzers kino bereits 20 Plätze reserviert sind, schlägt das folgende Update trotzdem fehl.

 

online> UPDATE kino.programm
SET kapazitaet = kapazitaet - 25
WHERE id = 1;

Error report -
ORA-02290: check constraint (KINO.SYS_C008756) violated

 

Für entsprechende Anwendungsfälle bieten die Sperrfreien Reservierungen damit eine sinnvolle Alternative zu klassischen Sperrmechanismen.

Weitere Neuerungen der Oracle Database 26ai lernen Sie in den Kursen Praxisworkshop New Features Oracle 26ai für DBAs und Praxisworkshop New Features Oracle 26ai für Entwickler kennen.

Kommentare

Keine Kommentare

Kommentar schreiben

* Diese Felder sind erforderlich