2017-12-18 2 views
0

Ich habe eine alte Client-Software, die eine verbundene Oracle-Datenbank für die Persistenz hat. Als Schnittstelle erlaubt die Client-Software nur den Aufruf von Funktionen und Prozeduren. Ich habe fast vollständigen Zugriff auf die Datenbank, d. H. Ich kann Funktionen und Prozeduren definieren. Wegen der Schnittstelle können nur Funktionen Werte zurückgeben und ich kann die Parameteroption OUT der Prozeduren nicht verwenden.DML in einem Funktionsaufruf

Jetzt will ich einfach einen Wert aus einer Tabelle lesen:

SELECT value FROM myTable WHERE id = 42; 

Und erhöhen Sie den Wert danach:

UPDATE myTable SET value = value + 1 WHERE id = 42; 

ich eine Funktion für die select-Anweisung und ein Verfahren für die Verwendung könnte aktualisieren und beide nacheinander aufrufen. Das Problem hier ist das Nichtvorhandensein von Transaktionen auf der Client-Seite. Daher kann ein anderer Thread zwischen Auswählen und Aktualisieren falsche Werte erhalten.

Also meine Frage ist, wie kann ich beide Anrufe in einer Transaktion verwenden, ohne Transaktionen ...

Versuchte Ansätze:

  • Verwenden anonymen PL/SQL-Blöcke -> die Syntax nicht vom Client unterstützt.
  • Setzen Sie beide Aufrufe in einer einzigen Funktion -> DML ist in einer Select-Anweisung nicht erlaubt.
  • PRAGMA AUTONOMOUS_TRANSACTION -> Ich habe gehört, es ist eine schlechte Sache und sollte nicht verwendet werden.
+2

'Functions' sollen *** nicht *** haben Nebenwirkungen Wenn Sie möchten, Um den Zustand der Datenbank zu ändern, müssen Sie eine 'Prozedur 'verwenden. – MatBailie

+1

Wenn Sie einen einfachen' Zähler 'möchten und in diesem Szenario nichts anderes vor sich geht, könnten Sie' SEQUENZ ERSTELLEN' in Erwägung ziehen? – MatBailie

+0

Wenn ich benutze das Verfahren (und kann 'OUT' nicht verwenden), ich brauche zwei Datenbankaufrufe, die nicht Thread speichern – Thanthla

Antwort

1

Sie kann tun DML in einer Funktion, wie unten gezeigt, aber ich betone - hüte die anderen Kommentare. Sehen Sie sich eine Sequenz an (auch mehrere Sequenzen), weil das Ausführen von DML in einer Funktion generell eine schlechte Idee ist, da die Anzahl der Ausführungen eines Funktionsaufrufs (wenn von SQL aus aufgerufen) nicht deterministisch ist. Außerdem treten Probleme mit der Skalierbarkeit auf, wenn sie in großen Mengen verwendet werden. Und in einer Umgebung mit mehreren Benutzern müssen Sie Sperren/Serialisierung verarbeiten, sonst erhalten mehrere Sitzungen den gleichen Integer-Wert zurückgegeben.

So ... nach allem, Sie noch

:-(diesen Weg gehen möchten.
SQL> create table t (x int); 

Table created. 

SQL> insert into t values (0); 

1 row created. 

SQL> 
SQL> create or replace 
    2 function f return int is 
    3 pragma autonomous_transaction; 
    4 retval int; 
    5 begin 
    6 update t 
    7 set x = x + 1 
    8 returning x into retval; 
    9 commit; 
10 return retval; 
11 end; 
12/

Function created. 

SQL> 
SQL> select f from dual; 

     F 
---------- 
     1 

1 row selected. 

SQL> select * from t; 

     X 
---------- 
     1 

1 row selected. 

SQL> select f from dual; 

     F 
---------- 
     2 

1 row selected. 

SQL> select * from t; 

     X 
---------- 
     2 

1 row selected. 

SQL> select f from dual; 

     F 
---------- 
     3 

1 row selected. 

SQL> select * from t; 

     X 
---------- 
     3 

1 row selected. 
+0

Vielen Dank für Ihre Antwort. Ich kannte deine vorgeschlagene Lösung und die Probleme damit. Daher werde ich höchstwahrscheinlich die Konsistenz verlieren und die Funktion zum Lesen und die Prozedur zum Aktualisieren ausführen. Die Wahrscheinlichkeit, dass zwei Threads diesen Workflow interleaved ausführen, ist so gering, dass ich das Risiko eingehen kann. – Thanthla

Verwandte Themen