Bevorzugte Möglichkeit, Delphi-Datenbank-Apps mit Transaktionen und datensensitiven Komponenten zu schreiben

8

Was ist der beste Weg, Delphi-Datenbankanwendungen mithilfe von Transaktionen und auch datensensitiven Komponenten zu schreiben?

Ich muss eine Client-App schreiben, die auf InnoDB-Tabellen zugreift, und einige Details in Transaktionen erledigen. Nach einigen Recherchen zu Transaktionen (aus allgemeiner Sicht) bin ich demütig zu dem Schluss gekommen, dass nicht datensensitive Komponenten und handcodiertes SQL die "perfekte Übereinstimmung" von Transaktionen darstellen würden. Aber die datensensitiven Komponenten wären nicht. Sie scheinen nicht füreinander gemacht zu sein.

Ich habe die reale Notwendigkeit, Transaktionen zu verwenden, aber andererseits konnte ich nicht einfach die datenbewussten Komponenten wegwerfen, weil sie die Dinge stark vereinfachen.

Könnte jemand bitte mich erleuchten? Ich habe es gegoogelt, aber ich habe keine nützliche Antwort gefunden. Vielleicht, weil mein Englisch nicht gut genug ist, dass meine Keywords begrenzt sind.

Übrigens, ich benutze Delphi 7 und evaluiere derzeit UniDAC als Datenzugriffsbibliothek.

Danke.

BEARBEITEN

Beispiel, um einen Aspekt meiner Frage zu beschreiben:

Stellen Sie sich ein Formular mit 2 DBGrids vor. Das erste Raster ist MasterGrid und darüber befinden sich diese Schaltflächen: Add, Edit & amp; Löschen. Das zweite Raster ist DetailGrid. Wenn der Benutzer auf Hinzufügen klickt, dann sieht das so aus:

  • Verbindung.StartTransaktion
  • Master.Append then Master.Post then Master.Edit (so dass der Hauptdatensatz den Primärschlüssel autoincrement besitzt und jetzt editierbar ist)
  • Zeigen Sie das Bearbeitungsformular modal an, in dem der Benutzer die Stammdatensätze füllt, und fügen Sie auch einige Detaildatensätze mit einem anderen Formular hinzu.
  • Wenn der Benutzer auf "OK" klickt, führt die App "Master.Post" und "Connection.Commit" aus. Wenn der Benutzer auf Abbrechen klickt, würde die App Connection.Rollback.
  • ausführen

Ich weiß, dass Transaktionen so kurz wie möglich sein sollten, aber Sie können oben sehen, dass die Transaktion nur so kurz ist wie die Geschwindigkeit des Benutzers, der das Formular ausfüllt.

Wenn ich nicht datensensitive Komponenten verwenden würde, würde ich benutzerdefinierte SQL-Einfügungen basierend auf Benutzereingaben vornehmen und dann SQL zwischen StartTransaction und Commit ausführen. So kann ich eine sehr kurze Transaktion erreichen.

BEARBEITEN 2

Ich danke Ihnen allen für Ihre freundliche Teilnahme. Ich wähle die Antwort von vcldeveloper, weil es die nächste Lösung für meinen aktuellen Bedarf ist.

    
Cocin 30.09.2010, 18:01
quelle

5 Antworten

3

Andere haben erwähnt, dass Sie eine Kombination aus DatasetProvider und ClientDataset verwenden, um eine Stapelaktualisierung durchzuführen. Wenn ADO- oder UniDAC-Komponenten verwendet werden, benötigen Sie die zusätzliche Schicht von DatasetProvider + ClientDataset nicht, da sowohl ADO als auch UniDAC Stapelupdates unterstützen / p>

Bei ADO sollten Sie LockType Ihrer Datenmenge auf ltBatchOptimistic setzen. Für UniDAC sollten Sie die Eigenschaft CacheUpdate auf True setzen.

Durch diese Änderung speichert Ihre Datenmenge alle Änderungen, die Sie an der speicherinternen Datensatzgruppe vorgenommen haben, und sendet sie nur dann an die Datenbank, wenn Sie die Methode UpdateBatch (ADO) oder ApplyUpdates

Nun sollten Sie Ihren Benutzer einen Datensatz im Master-Dataset einfügen und ihn bearbeiten lassen, und zwar unabhängig von den Daten, die er möchte. Alle Änderungen würden zwischengespeichert werden. Wenn Ihr Benutzer fertig ist, können Sie eine neue Transaktion starten und zuerst UpdateBatch (oder ApplyUpdate im Fall von UniDAC) für den Hauptdatensatz und dann für den Detaildatensatz aufrufen, und wenn alles gut geht, die Transaktion festschreiben.

>

Dadurch werden Ihre Transaktionen kurz, ohne die zusätzliche Schicht von ClientDataset zu benötigen.

Grüße

    
vcldeveloper 01.10.2010, 02:27
quelle
5

Ich verstehe Ihre Frage, denke ich. Wenn ein TADODataSet mit z.B. In 10 Datenzeilen, die in einem Formular bearbeitet werden sollen, mit datensensitiven Komponenten gibt es Situationen, in denen Sie alle an allen 10 Zeilen vorgenommenen Änderungen (und möglicherweise Löschungen und Einfügungen) zwischenspeichern und als einen Stapel festschreiben möchten . Sie können die Transaktion bei der ersten Änderung nicht öffnen, da dies andere Benutzer daran hindern würde, dieselben Daten zu ändern. Transaktionen sollten so kurz wie möglich sein.

Was ich im skizzierten Szenario mache, ist die Verwendung der folgenden Komponenten in einer Kette:

TADOConnection & gt; & gt; TADODataSet & gt; & gt; TDataSetProvider & gt; & gt; TClientDataSet & gt; & gt; TDataSource & gt; & gt; TDBEdits etc.

Jetzt werden alle Änderungen in TClientDataSet zwischengespeichert und Sie können ihre Methode ApplyUpdates aufrufen, um alle Änderungen in einer schnellen Transaktion zu posten. Beachten Sie, dass es auch möglich ist, mehrere TADODataSets und mehrere TClientDataSets für eine Master-Detail-Struktur (-detail usw.) mit verschachtelten Datasets zu verwenden. Alle Master-Detail-Änderungen können auch in einem Batch in einer Transaktion zwischengespeichert und angewendet werden. Weitere Informationen zur Implementierung finden Sie in der Hilfe und den Ressourcen an anderer Stelle. Am Anfang ist es nicht einfach. Aber wenn Sie es herausgefunden haben, ist es einfach und bietet jede Menge Möglichkeiten. (Offline-Bearbeitung, Überprüfung von Änderungen vor der Anwendung usw.)

    
MvdH 30.09.2010 18:58
quelle
2

Um große Transaktionen zu vermeiden, verwende ich DataSetProvider und ClientDatasets (auch lokal).

Betrachten Sie dies als eine Art Cache und es gibt Ihnen das Beste aus beiden Welten. Sie können datensensitive Steuerelemente verwenden, um die Arbeit auf der Benutzeroberfläche zu vereinfachen. Benutzeraktionen über die Datensätze werden von den ClientDataSets (Art des Datenbankcaches) "aufgezeichnet".

Wenn Ihr Benutzer bereit ist, die Änderungen an der Datenbank zu speichern (beispielsweise sind alle Rechnungsdaten vorhanden), rufen Sie die Methode ApplyUpdates für das Dataset auf (s).

Im einfachsten Szenario, in dem sich alle Datensätze in einer Master-Detail-Beziehung befinden (verschachtelt vom Provider), startet und commitet der Provider die Transaktion selbst und setzt sie zurück, so dass Sie sich automatisch in einer Alles-oder-Nichts-Situation befinden. p>

Wenn Sie komplexere Beziehungen haben, können Sie StartTransaction aufrufen, bevor Sie Updates für alle beteiligten ClientDataSet-Sets anwenden und am Ende Commit oder Rollback (je nach Bedarf) aufrufen. Die Logik für den Anbieter ist, wenn die Verbindung eine aktive Transaktion hat, wenn ApplyUpdates aufgerufen wird. Dann führt sie nichts mit der Transaktion aus, sondern gibt lediglich Änderungen an der Datenbank aus, vorausgesetzt, Sie haben die Kontrolle über die Transaktion.

Sie müssen über TClientDataSet und den OnReconcileError lesen und mit der Technologie experimentieren, bevor Sie sie in Produktionsumgebungen einsetzen, aber es funktioniert sehr, sehr gut für mich.

Meine 2 Cent.

    
jachguate 30.09.2010 21:52
quelle
1

Sie haben absolut Recht, dass eine write Transaktion so kurz wie möglich sein sollte, und sie sollte nicht die ganze Zeit am Leben sein, während ein Benutzer das Formular ausfüllt.

Die allgemeine Lösung, wie bereits beantwortet, ist die Verwendung einer Zwischenschicht (ein ClientDataSet). Das eigentliche Problem mit Ihrem Szenario ist jedoch, dass Sie keinen Autoinkrement-Wert für die Master-Tabelle ohne Master.Append und Master.Post erhalten können. Daher starten Sie eine write Transaktion, lange bevor sie tatsächlich benötigt wird.

Wenn Sie also die Zwischenschicht nicht verwenden und trotzdem datensensitive Komponenten mit kurzen write -Transaktionen verwenden möchten, sollten Sie an eine Datenbank denken, die das Erhalten eines automatisch inkrementierten Werts ohne Ausführen von INSERT (to Stammtisch). Das Beispiel ist die Firebird -Datenbank und FibPlus-Datenzugriffskomponenten für Firebird unterstützen diese Funktion vollständig.

    
kludg 01.10.2010 00:38
quelle
0

Transaktionen sollten so kurz wie benötigt sein. Das Problem besteht darin, wie verschiedene Datenbanken mit Sperren umgehen. Datenbanken, die nur Sperren auf Zeilenebene ausführen und sofort ohne Warten aus einer Sperre zurückkehren können, haben eine weitaus geringere Wahrscheinlichkeit für Deadlock. In der Regel sind Einfügungen weniger problematisch (obwohl andere Benutzer je nach Isolationsstufe keine neuen Zeilen sehen, bis sie festgeschrieben werden), sind Aktualisierungen und Löschungen problematischer. Sich zu oft zu verpflichten, könnte auch "schlecht" sein. Das Zwischenspeichern von Änderungen und deren Anwendung in einer einzigen Operation ist eine weitere Möglichkeit. Sie müssen jedoch Probleme beheben, da andere Benutzer die Datensätze inzwischen ändern. Es gibt keine "bessere" Lösung - alles hängt von den tatsächlichen Bedürfnissen ab. Für einige Anwendungen (und für einige Datenbanken) ist das Speichern des Datensatzes, solange sie sich ändern, in Ordnung, für andere jedoch nicht. Batch-Updates können in einigen Szenarien in Ordnung sein, in anderen nicht. Sie müssen das Modell auswählen, das am besten für Ihre Anwendung und Ihre Datenbank geeignet ist.

    
user160694 30.09.2010 20:59
quelle