Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   GUI-Design mit VCL / FireMonkey / Common Controls (https://www.delphipraxis.net/18-gui-design-mit-vcl-firemonkey-common-controls/)
-   -   Delphi TIBCQuery funktionsweise ? (https://www.delphipraxis.net/200403-tibcquery-funktionsweise.html)

Int3g3r 17. Apr 2019 09:56

TIBCQuery funktionsweise ?
 
Guten Tag,

Kann mir jemand erklären wie die TIBCQuery komponente oder allgemein wie Query Komponenten funktionieren ?

Ich will wissen wo die abgefraten Daten abgelegt werden. Werden die Daten im Client-Memory abgelegt ?
Sind alle abgefragten Daten im Memory vorhanden bis zum nächsten Query ?
Oder wird bei jeder qryAnweisung der Server abgefragt ?

Beispiel
Delphi-Quellcode:
qryMitarbeiter.Open;
Name := qryMitarbeiterName.AsString;
Wird nun bei dem Befehl "qryMitarbeiterName.AsString;" eine Server abfrage gemacht? Order werden die Daten aus dem Client-Memory geholt?

Mfg Int3g3r

haentschman 17. Apr 2019 10:30

AW: TIBCQuery funktionsweise ?
 
Hallöle...8-)
Zitat:

Ich will wissen wo die abgefraten Daten abgelegt werden.
qryMitarbeiter.Open; -> Serverabfrage in ClientMemory
Name := qryMitarbeiterName.AsString; -> aus ClientMemory
Zitat:

sind alle abgefragten Daten im Memory vorhanden bis zum nächsten Query ?
Ja

Int3g3r 17. Apr 2019 11:27

AW: TIBCQuery funktionsweise ?
 
Zitat:

Zitat von haentschman (Beitrag 1430479)
Hallöle...8-)
Zitat:

Ich will wissen wo die abgefraten Daten abgelegt werden.
qryMitarbeiter.Open; -> Serverabfrage in ClientMemory
Name := qryMitarbeiterName.AsString; -> aus ClientMemory
Zitat:

sind alle abgefragten Daten im Memory vorhanden bis zum nächsten Query ?
Ja

Das habe ich auch zuerst gedacht. Wie wird dann aber sichergestellt das mein ClientMemory und die ServerDB aktuell sind ?
Folgendes Beispiel:

Applikation1 -> qryMitarbeiter.Open; -> Wird in ClientMemory geschrieben.
Applikation2 -> qryMitarbeiter.Open;
Applikation2 -> qryMitarbeiter.Post; (Es wurde ein Datensatz Editiert)

Somit wären meine ClientMemory Daten auf Applikation1 nicht mehr aktuell ... Diese müssten ja irgendwann aktualisiert werden, wann passiert das ? :|
Meist mache ich das .Open; beim FormActivate danach nicht mehr.

mkinzler 17. Apr 2019 11:33

AW: TIBCQuery funktionsweise ?
 
Stichwort Events

haentschman 17. Apr 2019 11:46

AW: TIBCQuery funktionsweise ?
 
Oh ha...:P
Du redest über Multi User Anwendungen. Da gelten andere Kriterien. :P
Zitat:

Diese müssten ja irgendwann aktualisiert werden, wann passiert das ?
Da gibt es den TButton...:wink: Damit kannst du die Datenmenge aktualisieren. Hohe Schule, und mehr Aufand, ist, sich von der Datenbank informieren zu lassen (Events), daß eine Aktualisierung nötig ist.

Dann solltest du dich informieren:
1: Locking Mechanismen (Datenbank oder eigenes) ... Frage: wer darf wann schreiben
2: Isolation Level https://de.wikipedia.org/wiki/Isolation_(Datenbank)

Du siehst, so einfach ist das nicht. In der Regel reicht ein "Refresh" Button. :wink:

Nachtrag:
Zitat:

Open; beim FormActivate
...keine gute Idee. http://docwiki.embarcadero.com/Libra...orm.OnActivate
Zitat:

sobald das Formular den Fokus erhält (wenn beispielsweise der Benutzer darauf klickt)
Willst du das?

Int3g3r 17. Apr 2019 12:33

AW: TIBCQuery funktionsweise ?
 
Aha, somit bin ich als Programmierer verantwortlich das ich im richtigen moment ein Refresh mache.
Hätte mir vorgestellt das mein DBMS ein Teil davon übernimmt.

Hauptsächlich ist es mir nur mal darum gegangen wo meine Daten liegen ob er bei jedem qryMitarbeiter eine DB-Abfrage macht.
Dies wurde ja beantwortet.

Besten Dank für die Hilfe!:-D

peterbelow 17. Apr 2019 12:33

AW: TIBCQuery funktionsweise ?
 
Zitat:

Zitat von Int3g3r (Beitrag 1430473)
Guten Tag,

Kann mir jemand erklären wie die TIBCQuery komponente oder allgemein wie Query Komponenten funktionieren ?

Ich will wissen wo die abgefraten Daten abgelegt werden. Werden die Daten im Client-Memory abgelegt ?
Sind alle abgefragten Daten im Memory vorhanden bis zum nächsten Query ?
Oder wird bei jeder qryAnweisung der Server abgefragt ?

Beispiel
Delphi-Quellcode:
qryMitarbeiter.Open;
Name := qryMitarbeiterName.AsString;
Wird nun bei dem Befehl "qryMitarbeiterName.AsString;" eine Server abfrage gemacht? Order werden die Daten aus dem Client-Memory geholt?

Mfg Int3g3r

Bei allen mir bekannten Server-Datenbanken läuft das so:

Query.Open schickt die Abfrage an den Server, und der Server erstellt einen Satz von Zeilen (Records), die den Bedingungen der Abfrage genügen, so wie zu diesem Zeitpunkt in der Datenbank existieren. Der Server hält dieses Ergebnis quasi vorrätig, solange die Query noch offen ist, oft als Teil einer automatischen Transaktion, die erst geschlossen wird, wenn die Query vom Client geschlossen wird. Aus diesem Satz von Records wird oft auch erstmal nur ein Teil an den Client zurückgegeben, der Rest dann erst, wenn der Client durch die Records scrolled (lazy fetch). Je nach Server und Art der Abfrage kann es sogar sein, das der Server zuerst nur einen Teil des Resultats zusammensucht und zurückgibt, den Rest dann erst, wenn der Client mehr Records anfordert (delayed fetch). Das ist z. B. der Grund, wieso man bei einer Query gemeinhin erst weis, wieviele Records sie liefert, wenn man bis zum letzten Record durchgescrollt hat.

Der Client kann, muss aber nicht, die bisher zurückgegebenen Records intern speichern. Verlassen kann man sich nur drauf, dass der aktive Record (der auf dem der Cursor der Query steht) vollständig im Client memory ist, und daher ein Zugriff auf dessen Felder keinen Serverzugriff auslöst. Eine Ausnahme sind mitunter BLOB-Felder, deren Inhalt oft erst vom Server geholt wird, wenn der Client ihn abfragt. Das sind alles Optimierungen, um den Datenverkehr zwischen Client und Server möglichst klein zu halten, da der Datentransfer früher (und oft auch heute noch) der limitierende Faktor für die Performance der Query war.

Der Server trifft aber auf jeden Fall Vorkehrungen dafür, dass der Client nur Records zurückbekommt, die der query zum Zeitpunkt ihrer Ausführung entsprechen. Wenn die Query längere Zeit offen bleibt und derweil Änderungen an dem Inhalt der Datenbank gemacht werden tauchen diese neuen Datensätze nicht automatisch im Resultat der Query auf, auch wenn sie der Abfrage entsprechen würden. Das kann für den Server ein ziemlicher Aufwand sein, er muß dafür quasi einen Snapshot der von der Query angesprochenen Tabellen erstellen und vorrätig halten, bis die Query geschlossen wird. Nur so kann sowas wie delayed fetch implementiert wwerden.

Wenn man also mit queries gegen eine Server-Datenbank arbeitet, sollte man immer
  • die query möglichst spezifisch formulieren, um einen möglichst kleinen Ergebnissatz zu erzeugen.
  • die query möglichst schnell wieder schließen, um die verwendeten Resourcen auf dem Server wieder freizugeben.

Wenn man die Daten aus der Query clientseitig länger braucht sollte man sie vollständig im Client speichern, z. B. in einem TClientDataset, oder (meine bevorzugte Methode) in einer Liste von Objekten.

Wenn der Client Änderungen an der Datenbank durch andere Beutzer mitbekommen muss, kann das aufwendig werden, je nach verwendeter Server-Datenbank. Interbase, Firebird und Oracle (die einzigen DBs die ich wenigstens ein bißchen kenne) haben eine Benachrichtigungsmechanismus, mit dem der Server dafür angemeldete Clients über interessante Änderungen informieren kann. Das erfordert aber gemeinhin auch einige server-seitige Programmierung (Trigger zumeist). Wenn die Datenbank sowas nicht anbietet sollte der Client dem Benutzer eine Refresh-Option für die angezeigten Query-Resultate anbieten, die die Query neu ausführt. Das automatisch alle x Sekunden zu machen ist normalerweise keine gute Idee, zumindest bei nicht lokal installierten Datenbanken.

haentschman 17. Apr 2019 13:02

AW: TIBCQuery funktionsweise ?
 
Zitat:

oder (meine bevorzugte Methode) in einer Liste von Objekten
:thumb: +1

Int3g3r 25. Apr 2019 10:44

AW: TIBCQuery funktionsweise ?
 
@peterbelow

Wow ! Top Erklärung besten Dank! :thumb:

Wenn nun zwei Transaktionen auf die gleiche Tabelle offen sind und beide User ändern den gleichen Datensatz werden die daten einfach überschrieben ist dies korrekt ?
Also die zuletzt geschriebenen Daten sind dann in der DB.

QryUser1.Open;
QryUser2.Open;
QryUser1.Edit (In Feld 'ABC' wird '500' eingetragen)
QryUser2.Edit (In Feld 'ABC' wird '600' eingetragen)
QryUser1.Post;
QryUser2.Post;
QryUser1.Close;
QryUser2.Close;

Was ist nun im Feld 'ABC' eingetragen ? '600' richtig ?
Macht es nun einen unterschied wer die Transaktion zuerst schliesst(qry.close)? (Laut deiner erklärung Ja.)
Wird mit dem Post in die Memory-Transaktion des Servers geschrieben oder direkt auf die DB ?

Mfg Int3g3r

hoika 25. Apr 2019 12:50

AW: TIBCQuery funktionsweise ?
 
Hallo,
da habe ich doch einen hübschen Artikel für Dich über Firebird und Transaktionen.

https://www.firebirdsql.org/

Zitat:

Wenn nun zwei Transaktionen auf die gleiche Tabelle offen sind und beide User ändern den gleichen Datensatz werden die daten einfach überschrieben ist dies korrekt ?
Nein, wenn das so wäre, wäre es schön doof.
In diesem Fall erhält die letzte Transaktion eine DB-Exception.
Genau deshalb sollte man Transaktionen möglichst kurz halten.

Zitat:

Macht es nun einen unterschied wer die Transaktion zuerst schliesst(qry.close)?
Query.Post schließt (Commit) keine Transaktion, es sei denn es ist AutoCommit eingestellt.

PS:
Die Benutzung von Query.Edit/Post habe ich nie verstanden.

peterbelow 25. Apr 2019 16:59

AW: TIBCQuery funktionsweise ?
 
Zitat:

Zitat von Int3g3r (Beitrag 1430936)
@peterbelow

Wow ! Top Erklärung besten Dank! :thumb:

Wenn nun zwei Transaktionen auf die gleiche Tabelle offen sind und beide User ändern den gleichen Datensatz werden die daten einfach überschrieben ist dies korrekt ?
Also die zuletzt geschriebenen Daten sind dann in der DB.

QryUser1.Open;
QryUser2.Open;
QryUser1.Edit (In Feld 'ABC' wird '500' eingetragen)
QryUser2.Edit (In Feld 'ABC' wird '600' eingetragen)
QryUser1.Post;
QryUser2.Post;
QryUser1.Close;
QryUser2.Close;

Was ist nun im Feld 'ABC' eingetragen ? '600' richtig ?
Macht es nun einen unterschied wer die Transaktion zuerst schliesst(qry.close)? (Laut deiner erklärung Ja.)
Wird mit dem Post in die Memory-Transaktion des Servers geschrieben oder direkt auf die DB ?

Mfg Int3g3r

Das clientseitige Framework kompliziert die Sache erheblich und macht das Ganze undurchsichtig, was das Verständnis erschwert. Wenn man direkt mit SQL arbeitet ist Sequenz der Ereignisse deutlich einfacher zu erkennen. Zuerst mal ist die Abfrage nicht direkt mit dem Update eines Datensatzes verknüpft. Das sieht nur so aus, weil das Client-Framework so konstruiert ist. Was aber auf der SQL-Ebene passiert sind zwei völlig separate Aktionen, die auch normalerweise in verschiedenen Transaktionn abgewickelt werden.

Vereinfacht macht das Framework in etwa folgendes:

Abfrage:
SELECT <fieldlist> FROM tablename WHERE condition1;

Update:
try
UPDATE tablename SET field1 = value, field2 = value ....
WHERE condition2;
COMMIT;
except
ROLLBACK;
raise
end;

Der Knackpunkt ist hier folgender: condition1 liefert normalerweise eine ganze Reihe von Zeilen zurück. Für das UPDATE muss condition2 aber so formuliert sein, das damit exakt eine Zeile in der Tabelle identifiziert wird, nämlich die, die der Benutzer gerade editiert hat. Die einzig generelle Methode, das zu machen (und gleichzeitig die am wenigsten effiziente) ist es, einfach für alle nicht-LOB Felder in der WHERE-Klausel eine Bedingung der Art feld = orginalwert anzugeben. Damit findet der Server den zu ändernden Record nur, wenn er noch nicht von einem anderen Benutzer geändert wurde. Wenn der Record nicht gefunden wird gibt der Server zurück, dass 0 Records geändert wurden, der Client erzeugt daraufhin eine Exception, und (bei automatischen Transaktion-Handling) die Transaktion wird zurückgerollt.

Wenn 2 Clients also parallel den gleichen Datensatz bearbeiten gewinnt der, der zuerst das COMMIT ausführt. Erst dann wird der vom UPDATE-Statement erzeugte Datensatz aus der Transaktion der Session in die Datenbank geschrieben.

Wie parallele Transaktionen sich auswirken hängt maßgeblich davon ab, wie die WHERE-Klausel des UPDATE-Statements aufgebaut wird. Im Prinzip kann man da z. B. nur den primary key des Datensatzes verwenden. Da sich der aber nie ändert würde man damit aber Kollisionen zwischen Transaktionen nicht erkennen, dann würde das zweite COMMIT eventuell Änderungen des ersten überschreiben. Wenn man das vermeiden will und trotzdem effiziente UPDATEs haben will erfordert das mehr Arbeit, z. B. eine Versionnummer in einem Feld der Tabelle, die nach jedem Update automatisch von einem Trigger hochgezählt wird. Dann kann man die Kombination primary key + Versionsnummer verwenden, um den Datensatz auszuwählen und hat trotzdem eine effiziente Kollisionsdetektion. Nachteil: man muss die Versionsnummer nach dem Update in der clientseitigen Version aktualisieren. All das in diesem Absatz kannst Du im Prinzip vergessen, wenn Du mit data-bound controls und einem der mit Delphi gelieferten data access frameworks arbeitest, da hat man einfach nicht genug Kontrolle über die Details.

hoika 25. Apr 2019 17:04

AW: TIBCQuery funktionsweise ?
 
Hallo,
Zitat:

Wie parallele Transaktionen sich auswirken hängt maßgeblich davon ab, wie die WHERE-Klausel des UPDATE-Statements aufgebaut wird.
Einspruch, Euer Ehren ;)

Wir reden hier von Interbase/Firebird.
Da spielt die MGA schon eine größere Rolle (Multi-Generationen-Architektur).

peterbelow 25. Apr 2019 17:10

AW: TIBCQuery funktionsweise ?
 
Zitat:

Zitat von hoika (Beitrag 1430966)
Hallo,
Zitat:

Wie parallele Transaktionen sich auswirken hängt maßgeblich davon ab, wie die WHERE-Klausel des UPDATE-Statements aufgebaut wird.
Einspruch, Euer Ehren ;)

Wir reden hier von Interbase/Firebird.
Da spielt die MGA schon eine größere Rolle (Multi-Generationen-Architektur).

Ich kenne mich halt hauptsächlich mit Oracle aus.

hoika 25. Apr 2019 17:15

AW: TIBCQuery funktionsweise ?
 
Hallo,
ah, OK.

Siehe mein Post auf der ersten Seite.
Zusammenfassung: Firebird bekommt mit, dass nach dem Starten einer Transaktion ein anderer
Nutzer den Datensatz geändert hat, und verhindert das Commit.
Gerade, um Datenverlust zu vermeiden, in dem Fall die Daten dessen, der zuerst gespeichert (commited) hat.

peterbelow 26. Apr 2019 03:32

AW: TIBCQuery funktionsweise ?
 
Zitat:

Zitat von hoika (Beitrag 1430966)
Hallo,
Zitat:

Wie parallele Transaktionen sich auswirken hängt maßgeblich davon ab, wie die WHERE-Klausel des UPDATE-Statements aufgebaut wird.
Einspruch, Euer Ehren ;)

Wir reden hier von Interbase/Firebird.
Da spielt die MGA schon eine größere Rolle (Multi-Generationen-Architektur).

Sch... wetware, da hat sich doch ein Hintergrundprozess in dem Problem verbissen und mußte mich unbedingt mitten in der Nacht wecken, um mir das Ergebnis mitzuteilen. Und jetzt kann ich nicht mehr einschlafen :x...

Der Einspruch wurde abgewiesen, allerdings mit der Maßgabe, das es von der Interpretation des Wortes "parallel" abhängt, was denn da relevant ist. Redet man von zeitlich verschachtelten Transaktionen, (A führt ein Update aus, B tut das gleiche für den gleichen Datensatz bevor A committed ist) ist der Einwand richtig. Diese Art der Kollision kann der Server detektieren und abweisen.

Mir ging es aber mehr um Transaktionen, die zwar den gleichen Datensatz verändern, aber zeitlich soweit getrennt sind, das A bereits committed ist wenn B ausgeführt wird. Das ist ein wesentlich praxisnäheres Scenario. In diesem Scenario kann der Server die Kollision nicht detektieren, da bei Ausführen des Updates von B keine offene Transaktion für den gleichen Datensatz mehr existiert. Selbst wenn er feststellt, dass er mehr als eine Version des Datensatzes in "Generationen" hat, die noch nicht mit der Master-Version der Tabelle gemerged wurden, kann er deswegen das Update nicht abweisen, dann könnte man ja einen Datensatz nicht wieder editieren, bevor dieser Abgleich durchgeführt wurde. Das wäre ein nicht akzeptables Verhalten aus der Sicht des Benutzers.

Nein, der Server kann das Kollisionsproblem nur teilweise lösen, wirklich lösen kann es nur der Programmierer bzw. DB designer, in dem er sich des Problems bewusst ist und entsprechende Vorkehrungen trifft, mit denen ein Client sicherstellen kann, das er einen Datensatz nur verändert, wenn er noch in dem Zustand ist, in dem er gelesen wurde.

So, vielleicht kann ich jetzt wieder einschlafen...

hoika 26. Apr 2019 05:51

AW: TIBCQuery funktionsweise ?
 
Guten Morgen ;)

Zitat:

Mir ging es aber mehr um Transaktionen, die zwar den gleichen Datensatz verändern, aber zeitlich soweit getrennt sind, das A bereits committed ist wenn B ausgeführt wird.
bereits committed ist wenn B ausgeführt/ die Transaktion startet.

Ja, in diesem Fall kann das nur der Programmierer lösen.

Gute Nacht ;)


Alle Zeitangaben in WEZ +1. Es ist jetzt 05:00 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz