PDA

View Full Version : *LCKSPC



wti
30-08-17, 13:45
Hi @ll,

ich muss das Thema noch Mal aufgreifen.

In den Beiträgen, die ich gefunden habe, geht es immer darum dass eine *LCKSPC aufgelöst werden muss.
Bei uns wird der *LCKSPC bewusst erzeugt: Unsere Anwendung für die Pflege von Stamm-Daten auf einer neuen DB-Struktur wird mit .NET (Entity-Framework) erstellt. Die Daten werden über Trigger an den neuen Tabellen, in die "Alte Welt" geschrieben.
Die Verbindung zum System i erfolgt über DB2Connect.

Um alle Änderungen eines Verarbeitungsschrittes zusammenzufassen, wird zu Beginn des Updates eine XA Transaktion gestartet (New Transaction).
Damit werden alle Aktionen zusammengefasst, wobei am Ende ein Commit oder Rollback erfolgt.
Diese Funktionalität bewirkt allerdings auch, dass auf jeder Tabelle, die innerhalb der XA-Transaktion geschrieben/fortgeschrieben wird ein *LCKSPC gesetzt wird.

Dies führt dann zu dem unschönen Ergebnis, dass die Trigger-Verarbeitung auf die gerade geschriebenen Daten nicht zugreifen kann.
Diese Zugriffe sind aber zwingend erforderlich, da spezielle Prüfungen auf die geschriebenen Daten notwendig sind um den richtigen Zeitpunkt für das Triggern in die "Alte Welt" zu ermitteln.

Ich hoffe dass ich das Problem verständlich beschrieben habe und irgendjemand eine Idee hat wie dieses Problem zu umgehen ist, bzw. welcher "Parameter/Schlüsselwort" einen Zugriff ermöglicht.

VG
wti

Fuerchau
30-08-17, 14:14
Alle Daten, die innerhalb einer Transaktion geändert/erstellt wurden sind beliebig oft von derselben Transaktion änderbar.
Dies betrifft ebenso die Trigger. Das Problem tritt ggf. dann auf, wenn die Trigger in einer eigenen ACTGRP statt *CALLER laufen, somit eigene Transaktionen erstellen und diese ggf. nicht committen.
Die Trigger müssen ggf. auch mit Änderungserlaubnis der Daten eingerichtet sein, sonst sind Änderungen an den Daten selber (after-Trigger) oder der Pufferdaten (Before-Trigger) nicht möglich bzw. sie werden ignoriert.

BenderD
30-08-17, 14:25
... wo ist denn die "neue Welt" und wo die "alte", alles auf der AS/400? Dann brauchst Du keine XA Transaktion, dann wird eine neu Transaktion mit der ersten Schreiboperation nach dem Commit/rollback automatisch gestartet. Die TRigger, soweit sie auf der AS/400 sind, müssen mit allow repeatable change *YES erstellt werden und die Daten selber brauchen sie nicht lesen, die kriegen sie automatisch.

D*B

wti
30-08-17, 15:12
Danke erst mal für die Antworten.

Die "Neue Welt" ist ebenfalls auf dem System i, aber der Update aus der .NET-Anwendung über das EF erfolgt in mehreren Schritten, die zu einer gemeinsamen Transaktion zusammengefasst werden müssen.

Auf der Suche nach der Aktivierungsgruppe für den Trigger bin ich darauf gestoßen, dass das Trigger-Programm mit der ACTGRP *CALLER erstellt wird:

Programm . . . . . . . : TR_PA00012 Bibliothek . . . . . . : TEST100
Eigner . . . . . . . . : PROGRAMMER
Programmattribut . . . : CLE
Detail . . . . . . . . : *BASIC

Informationen zur Programmerstellung:
Programmerstellungsdatum/-zeit . . . . . . . . : 16.08.17 19:02:50
Programmart . . . . . . . . . . . . . . . . . : ILE
Modul der Programmeingangsprozedur . . . . . . : TR_PA00001
Bibliothek . . . . . . . . . . . . . . . . . : QTEMP
Attribut der Aktivierungsgruppe . . . . . . . : *CALLER
Gemeinsam benutzte Aktivierungsgruppe . . . . : *NO
Benutzerprofil . . . . . . . . . . . . . . . . : *OWNER
Übernommene Berechtigung verwenden . . . . . . : *YES

...der erzeugte Job dann aber *DFTACTGRP verwendet, was dazu führt dass auf die Daten nicht zugegriffen werden kann.

Job: QRWTSRVR Benutzer: QUSER Nummer: 280688

Thread . . . . . . . . . . . . . : *NONE
ID der logischen Arbeitseinheit . : APPN.COR...
Sperrbereichs-ID . . . . . . . . : UDB_010000000019FD71
COMMIT-Definition . . . . . . . . : *DFTACTGRP
Aktivierungsgruppe . . . . . . . : 2
ASP-Gruppe . . . . . . . . . . . : *SYSBAS

Ressourcenstandort . . . . . . . : LOKAL
Standardsperrstufe . . . . . . . : *CS
Benutzer . . . . . . . . . . . . : DST_CORE

Wie bringe ich den Trigger dazu auch bei dem Aufruf die ACTGRP *CALLER zu verwenden, wie sie im Objekt eingetragen ist???
Oder interpretiere ich die Angaben falsch?

Die Trigger - so wie sämtliche Procedures, Functions etc. - werden in RDi entwickelt und auch aus RDi heraus als Objekte erstellt. Es handelt sich um reine SQL-Trigger.

wti

BenderD
30-08-17, 15:28
... SQL Trigger haben immer allow repeatable change und den Satz müssen die nicht lesen, man muss nur einen before trigger erstellen und das before Abbild deklarieren. Eine XA Transaktion brauchst Du dafür allenfalls, wenn Du eine verteilte Transaktion hast, also auf mehreren Rechnern schreibst, aber auch da ist das keineswegs zwingend. Von den ACTGRPs ist das ebenfalls alles in Ordnung. Du musst nur in deinem .NET sicherstellen, dass alles über dieselbe Connection geht, oder eben alle Connectens committen, bzw. zurücksetzen.

D*B

wti
30-08-17, 15:58
ganz so einfach scheint das mit .NET und dem EntityFramework nicht zu sein - ich bin kein Fachmann in dem Bereich und sammle mir meine Informationen bei den Kollegen :)

Natürlich wird ein Stammsatz in der Anwendung auf mehreren Tabellen verteilt - jede Tabelle wird aus dem EF als eine Transaktion fortgeschrieben. Auf jeder Tabelle gibt es einen Trigger, der die Daten in die "Alte Welt" schreibt.
Diese Verarbeitung muss in einer Transaktion zusammengefasst werden, da weder die Tabellen einzeln gespeichert werden dürfen, noch die Trigger-Operation bei einem Abbruch zurückbleiben darf.
Zudem dürfen die Daten - bei einer Neuanlage - erst in die "Alte Welt" getriggert werden, wenn alle Tabellen der "Neuen Welt" geschrieben worden sind. Aus diesem Grund muss in den Triggern bei jeder Tabelle der "Neuen Welt" durch lesende Zugriffe auf die gerade geschriebenen Sätze geprüft werden, ob alle Informationen für die Weitergabe in die "Alte Welt" vorhanden sind.
Für diese Beurteilung reichen die Informationen der aktuell bearbeiteten Tabelle, die der Trigger im Zugriff hat, nicht aus.
Außerdem haben wir auch mehrere Connection-Strings für unterschiedliche Bereiche von Daten.

Hört sich kompliziert an - ist es aber auch :)

Ich muss also erreichen, dass der Trigger in der gleichen ACTGRP läuft wie der Update aus dem EF.

In der Anzeige der Objekt-Sperre steht in der ersten Zeile der Lock aus dem EF und der zweite Job darunter ist die Trigger-Verarbeitung (ACTGRP s.o.):

Aus-
wahl Job Benutzer Sperre Status Bereich Thread
*LCKSPC *SHRRD HELD *LCKSPC
QRWTSRVR QUSER *SHRRD HELD *JOB
QRWTSRVR QUSER *SHRRD HELD *JOB
*SHRRD HELD *JOB
*SHRRD HELD *JOB
*SHRRD HELD *JOB
*SHRRD HELD *JOB

Die Trigger-Verarbeitung verabschiedet sich dann mit folgender Meldung:

Satz 17422 wird von Job /000019FD79/XATL010000 benutzt.
Satz 17422 wird von Job /000019FD79/XATL010000 benutzt.
Zeile oder Objekt PARTNER der Art *FILE in PROD100 wird verwendet.
Zeile oder Objekt PARTNER der Art *FILE in PROD100 wird verwendet.
Fehler bei benutzerdefinierter Funktion in Teildatei QSQPTABL.
Fehler bei benutzerdefinierter Funktion in Teildatei QSQPTABL.
Zeile oder Objekt PARTNER der Art *FILE in PROD100 wird verwendet.
Zeile oder Objekt PARTNER der Art *FILE in PROD100 wird verwendet.
Zeile oder Objekt PARTNER der Art *FILE in PROD100 wird verwendet.
Zeile oder Objekt PARTNER der Art *FILE in PROD100 wird verwendet.
SQL-Auslöser TR_PARTNER_UPD in PROD100 ist mit SQLCODE -913 SQLSTATE 57033
fehlgeschlagen.

wti

BenderD
30-08-17, 16:53
... mit der ACTGRP hat das nix zu tun (das ist eine Unterteilung eines Jobs). Wenn das EF mehrere connections (das sind dann mehrere Programme) innerhalb einer Transaktion benutzt, dann ist euer design mit den kreuz und quer lesenden Triggern ohnehin krumm - mit anderen Worten; kann das nicht gehen.

D*B

Fuerchau
30-08-17, 17:26
Auch das EntityFramework (EF) darf beim Update doch nicht mehrere Informationen aus unterschiedlichen Tabellen in jeweils eine Transaktion packen!
Dann kannst du auch gleich ganz ohne Transaktionen arbeiten.
Wenn du im EF mehrere Aktionen durchgeführt hast und diese dann festschreiben willst, musst du auf Verbindungsebene (Database-Object) eine Transaktion starten, die dann alles durchführt.
Deine Altdateien werden im selben Journal wie die neuen Tabellen aufgezeichnet.
Deine Trigger können nun ebenso die Daten in die anderen Tabellen verteilen.
Erst wenn dann Database.Commit() ausgeführt wird, sind alle Änderungen konsistent fortgeschrieben.

Eine Transaktion über mehrere Verbindungen gibt es nicht (so einfach)!
Dazu gehört eher Distributed Transaction, was hier aber keine Rolle spielt.

Selbst das Zusammenführen aus mehreren EF-Tabellen in eine Alttabelle innerhalb der Transaktion ist problemlos möglich.
Hier muss nur sinnvoll per Update/Insert/Update-Sequenz die Aktion durchgeführt werden. Dabei ist es unerheblich, welche der Teil-Tabellen denn zuerst geschrieben wurde.

https://msdn.microsoft.com/en-us/library/dn456843(v=vs.113).aspx