PDA

View Full Version : SQL Stored Procedures u. ThreadSafety



Seiten : [1] 2

axl
14-07-08, 06:34
Hallo zusammen,

ich benutze eine SQL-Procedure um ein Resultset nach Prüfung der Berechtigung an den Client (in diesem Fall Java) zurückzugeben.

Das Ganze funktioniert auch zu 99% ganz gut, aber eben nur zu 99%. Irgendwie erhält der Client manchmal das falsche Resultset zurück.
Dies passiert, wenn zwei Java-Threads in sehr kurzen Zeitabständen ein Resultset über diese SQL-Procedure anfordern.
Auch wenn ich den Zugriff mittels 'synchronize' in der Java-Methode serialisiere taucht dieses Phänomen immer noch auf.

Unser Versionsstand ist V5R2.

Für eine Antwort wäre ich sehr dankbar. Auch für einen evtl. anderen Lösungsansatz bzgl. Resultsets u. Berechtigungsprüfung.

Fuerchau
14-07-08, 08:01
Ggf. liegt es an dem Attribut "[NOT] DETERMNINISTIC" !


DETERMINISTIC or NOT DETERMINISTIC Specifies whether the procedure returns the same results each time the procedure is called with the same IN and INOUT arguments.
NOT DETERMINISTIC The procedure may not return the same result each time the procedure is called with the same IN and INOUT arguments, even when the referenced data in the database has not changed.
DETERMINISTIC The procedure always returns the same results each time the procedure is called with the same IN and INOUT arguments, provided the referenced data in the database has not changed.

B.Hauser
14-07-08, 08:21
Hallo,

ich würde eher FENCED bzw. NOT FENCED vorschlagen. Dieses Schlüssel-Wort ist bereits V5R2 sowohl beim CREATE PROCEURE als auch beim CREATE FUNCTION verfügbar:

FENCED or NOT FENCED
Specifies whether the external function runs in an environment that is isolated from the database manager environment. FENCED is the default.

FENCED
The function will run in a separate thread.
FENCED functions cannot keep SQL cursors open across individual calls to the function. However, the cursors in one thread are independent of the cursors in any other threads which reduces the possibility of cursor name conflicts.

NOT FENCED
The function may run in the same thread as the invoking SQL statement.
NOT FENCED functions can keep SQL cursors open across individual calls to the function. Since cursors can be kept open, the cursor position will also be preserved between calls to the function. However, cursor names may conflict since the UDF is now running in the same thread as the invoking SQL statement and other NOT FENCED UDFs.
NOT FENCED functions usually perform better than FENCED functions.

Bei DETERMINISTIC werden die Ausgabe-Werte (Parameter- und Result Sets) zwischen gespeichert. Beim nächsten Aufruf mit den gleichen Parametern, wird die Prozedur nicht ausgeführt, sondern lediglich das zuvor gesicherte Ergebnis ausgegeben.

Birgitta

Fuerchau
14-07-08, 10:56
Genau das DETERMINISTIC scheint ja das falsche Ergebnis zu bringen.

Ausserdem sollten verschiedene Threads nicht die selbe Connection sharen, das führt immer zu Problemen.

axl
15-07-08, 12:32
Vielen Dank für die schnellen Antworten, ich habe mal beide Schlüsselwörter ('NOT DETERMINISTIC, u. 'FENCED') integriert, wobei ich mit 'NOT DETERMINISTIC' schon auch rumprobiert hatte. 'FENCE' hatte ich allerdings noch nicht ausprobiert.

Auf jeden Fall schaut jetzt mein Procedure-Kopf folgendermaßen aus (siehe unten). Jetzt warte ich mal, wann dieser Fehler wieder auftritt...

Evtl. ist bei höheren Versionsständen (wir haben V5R2) dieses Phänomen beseitigt!?

-----------------------------------------
create procedure vogtj/SPTUNNEL(
IN actionname char(20)
)

result sets 1
language sql
NOT DETERMINISTIC
FENCED

BenderD
20-07-08, 10:14
das sieht mir eher nach einer fehlerhaften Implementierung im Java aus, die bei Verwendung einer extra Connection (aus einem ConnectionPool) für jeden SQL Zugriff nicht passieren kann.
Für alternative Lösungsansätze und Berechtigungsprüfungen bräuchte man schon ein wenig mehr Input.

D*B



Auch wenn ich den Zugriff mittels 'synchronize' in der Java-Methode serialisiere taucht dieses Phänomen immer noch auf.

Für eine Antwort wäre ich sehr dankbar. Auch für einen evtl. anderen Lösungsansatz bzgl. Resultsets u. Berechtigungsprüfung.

axl
23-07-08, 07:53
Das ist wahrscheinlich auch das Problem. Jede Abfrage (auch aus verschiedenen Threads) laufen über ein Connection Objekt.

Bisher funktionierte das auch wunderbar. Zumindest als wir noch direkt auf die Tabellen/Views zugegriffen haben.

Aber seit wir aus 'sicherheitsgründen' nur noch über Stored-Procedures zugreifen gibt's hier Probleme.

Bzgl. einer eigenen Connection pro SQL-Abfrage (ConnectionPool) wäre ich wahrscheinlich auf der sicheren Seite. Für mehr Infos diesbezüglich wäre ich Ihnen sehr dankbar.

BenderD
23-07-08, 08:53
Hallo,

normalerweise verwendet man bei JDBC (und nicht nur da) für jede Transaktion (-> sind bei Commit > 1 SQL Operation) grundsätzlich eine eigene Connection, das vereinfacht alles drastisch (auch die Threading Probleme sind damit automatisch ausgeschlossen). Damit nicht ständig Connections erzeugt und geschlossen werden, hält man sich diese in einem Connection Pool (davon gibt es mehrere OpenSource Implementierungen SourceForge.net: c3p0:JDBC DataSources/Resource Pools (http://sourceforge.net/projects/c3p0/) oder DBCP - Downloads (http://commons.apache.org/dbcp/downloads.html) ). Auf der AS/400 ist das zwar nicht so essentiell, weil da Server seitig eine Art Pool gehalten wird, aber bei externen Reviews sieht man ohne Pool eher schlecht aus.
Das ganze hat allerdings auch zur Konsequenz, dass in der Regel alle Datenbankzugriffe unter demselben Applikationsuser gemacht werden und die Zugriffskontrolle in die Applikation wandert, also gerade icht in einer stored Procedure abgefackelt werden. BTW: ich halte dieses Design für fragwürdig! User spezifische Sichten lassen sich in der Datenbank über inner join zu Berechtigungstabellen wesentlich eleganter und performanter lösen.
Wenn man spezifische Connections benötigt, dann sollte man trotzdem ConnectionPool dazwischen schalten (dann pro Benutzer ein Pool), der macht einiges mehr, wie Connections auf Gängigkeit prüfen, selbständig von Zeit zu Zeit neue zu nehmen, bis hin zum cachen von prepared Statements.

mfg

Dieter Bender

Das ist wahrscheinlich auch das Problem. Jede Abfrage (auch aus verschiedenen Threads) laufen über ein Connection Objekt.

Bisher funktionierte das auch wunderbar. Zumindest als wir noch direkt auf die Tabellen/Views zugegriffen haben.

Aber seit wir aus 'sicherheitsgründen' nur noch über Stored-Procedures zugreifen gibt's hier Probleme.

Bzgl. einer eigenen Connection pro SQL-Abfrage (ConnectionPool) wäre ich wahrscheinlich auf der sicheren Seite. Für mehr Infos diesbezüglich wäre ich Ihnen sehr dankbar.

axl
14-08-08, 08:37
Vielen Dank nochmals für die vielen Anregungen. Mittlerweile habe ich auf Connectionpools umgestellt. Wobei ich aber noch nicht nach jedem SQL eine 'neue' Connection verwende. Zumindest wird jetzt eine Connection auch nur von einem Thread verwendet.

Das Phänomen mit manchmal unsinnigen zurückgegeben Resultsets habe ich aber nach wie vor.

Unter: IBM - SE25763 - OSP-DB-MSGCPD4373 OR EMPTY RESULT SET (http://www-1.ibm.com/support/docview.wss?uid=nas2da21889c0305b81b86257174003c83 e0)
habe ich aber folgendes gefunden, wovon ich ausgehe, dass dies unser Phänomen genau beschreibt. Leider haben wir keine AS400 mit höherem Releasestand um dies auch bestätigen zu können.

BenderD
14-08-08, 08:57
auch der in deinem link beschriebene Fall ist eine grob fehlerhafte Implementierung in Java und kein Bug in der Datenbank:
private static PreparedStatement ps = null;
dieses Konstrukt ist Java seitig nicht Threadsafe!!!

mit solch einem Konstrukt kann ich soviele Connections verwenden, wie ich will - das preparedStatement wird unterm Hintern weg ausgetauscht, und das nicht nur über Threads, sondern über alle Objekte in der JVM, da schüttelts mich, und wenn ich in den Sandalen Socken anhätte, dann hätten meine sich hochrollenden Fußnägel Löcher hinterlassen.

Dieter Bender


Vielen Dank nochmals für die vielen Anregungen. Mittlerweile habe ich auf Connectionpools umgestellt. Wobei ich aber noch nicht nach jedem SQL eine 'neue' Connection verwende. Zumindest wird jetzt eine Connection auch nur von einem Thread verwendet.

Das Phänomen mit manchmal unsinnigen zurückgegeben Resultsets habe ich aber nach wie vor.

Unter: IBM - SE25763 - OSP-DB-MSGCPD4373 OR EMPTY RESULT SET (http://www-1.ibm.com/support/docview.wss?uid=nas2da21889c0305b81b86257174003c83 e0)
habe ich aber folgendes gefunden, wovon ich ausgehe, dass dies unser Phänomen genau beschreibt. Leider haben wir keine AS400 mit höherem Releasestand um dies auch bestätigen zu können.