Blog

Eine Suche nach generierten Schlüsseln in Kettle

Maarten Winkels

Aktualisiert Oktober 23, 2025
4 Minuten

In meinem aktuellen Projekt verwenden wir Kettle, um Daten aus einer Reihe von Quellen zu verarbeiten und in einer gemeinsamen Datenbank zu speichern. Kettle bietet großartige Unterstützung für das Parsen von Daten aus einer Vielzahl von Quellen, ihre Umwandlung und das Schreiben in eine Vielzahl von Zielen. Ein Problem, das häufig beim Einfügen von Daten in eine relationale Datenbank auftritt, ist die Notwendigkeit eines syntaktischen, eindeutigen Schlüssels, der beim Einfügen einer neuen Zeile erzeugt und später im Prozess für andere Zeilen verwendet wird, die sich auf die Primärzeile beziehen. Es gibt viele Lösungen für dieses Problem, sowohl im RDBMS als auch im Java-Bereich. Dieser Blog berichtet über die Suche nach einer guten Lösung in Kettle, die sich mir leider immer noch entzieht.

Das Problem wird dadurch noch komplizierter, dass es sowohl in der Produktionsumgebung als auch in unseren Kettle-Unit-Tests funktionieren soll. Für die Produktion verwenden wir Postgresql und für die Tests verwenden wir HsqlDB. An sich ist dies mit Kettle eine Herausforderung, aber durch die Verwendung eines generischen Datenbankkonnektors und die Injektion der JDBC-Eigenschaften über Variablen ist dies machbar. Sowohl Postgresql als auch HsqlDB bieten (in irgendeiner Form) Unterstützung für generierte Schlüssel: Postgresql Um eine auto-increment Spalte in Postgresql zu erstellen, verwenden Sie den (big)serial Datentyp. Dadurch wird eine einfache numerische Spalte erzeugt, die eine Sequenz besitzt, die für ihren Standardwert verwendet wird. Der Name der Sequenz ist tablename_columnname_seq. HsqlDB Ein Auto-Inkrement mit der folgenden Spaltendefinition: ... standardmäßig als Identität generiert (beginnt mit 1). Wenn eine Zeile eingefügt wird, die keinen Wert für die Auto-Inkrement-Spalte angibt, wird ihr Wert generiert, so weit so gut. Das Problem entsteht, wenn wir den generierten Wert für die gerade eingefügte Zeile benötigen. Und damit beginnt die Suche... JDBC3 -- Generierte Schlüssel Oberflächlich betrachtet, sollte dies ein einfaches Problem sein, da JDBC (seit v.3) über mehrere Schnittstellen Unterstützung für generierte Schlüssel bietet:

Der TableOutput-Schritt von Kettle verwendet diese Funktion, um die generierten Schlüssel für jede eingefügte Zeile zurückzugeben. Leider unterstützen weder HsqlDB (neueste Version 1.8.0.10) noch Postgres (neueste Version 8.4) diese Schnittstellen. Hibernate -- Inspiration In demselben Projekt verwenden wir Hibernate, um das Schema zu erstellen und mit den gesammelten und integrierten Daten zu arbeiten. Hibernate geht mit dieser Situation recht elegant um. Mit @GeneratedValue(strategy=IDENTITY) generiert es über seine spezialisierten Dialekte das richtige Schema sowohl für HsqlDB als auch für Postgresql.Um den generierten Wert zu holen, verwendet es die Funktion identity() auf HsqlDB und fragt Postgresql nach dem aktuellen Wert der Sequenz ab. Das funktioniert einwandfrei, obwohl man in hochgradig nebenläufigen Situationen Probleme erwarten könnte. Leider funktioniert das bei Kettle nicht, weil die Trennung der Einfügeanweisung und der Abfrage des generierten Schlüssels in zwei Schritten dazu führt, dass die Abfragen in separaten Threads laufen. So funktioniert Kettle. Um den letzten Sequenzwert für jede Zeile abrufen zu können, muss dies innerhalb desselben Schritts geschehen. Postgresql-spezifisch -- Inline-Lösungen Unterstützt Postgres, eine hochmoderne Datenbank, nicht eine Funktion, die es Ihnen ermöglicht, eine ID zu generieren und sie dann zu verwenden? Ist das nicht etwas, das sehr nützlich ist? Natürlich tut es das! Es wird eine benutzerdefinierte Syntax mit der folgenden Anweisung verwendet: INSERT INTO table (col1, col2, ...) VALUES (...) RETURNING col0 So weisen Sie Postgres an, den für die auto-increment Spalte generierten Wert in einem ResultSet zurückzugeben. Diese Anweisung sollte daher mit der Methode executeQuery() anstelle der Methode executeUpdate() ausgeführt werden und der Schritt TableOutput bietet dafür keine Unterstützung. Die Implementierung dieses Schritts ist im Großen und Ganzen ziemlich starr: Es gibt keine Punkte, die Sie angeben können, und kein benutzerdefiniertes SQL, das Sie ausführen können. Und natürlich unterstützt HsqlDB diese Syntax nicht, so dass wir eine Logik schreiben müssten, um zu bestimmen, was wann ausgeführt werden soll... Abfrage der Sequenz vor dem Einfügen Bei diesem Ansatz wird die Datenbanksequenz in einem separaten Schritt abgefragt , bevor die Daten in die Tabelle eingefügt werden. Er funktioniert (für Postgresql) einwandfrei, obwohl er die mit der Spalte verknüpfte Sequenz umgeht. Wir müssen manuell sicherstellen, dass wir die richtige Sequenz abrufen, um die beiden synchron zu halten. Bei HsqlDB wird nicht automatisch eine Sequenz für eine Identitätsspalte erstellt. Wir müssen die Sequenzen manuell zum Schema hinzufügen. Auch die Syntax für die Abfrage einer Sequenz ist bei HsqlDB anders. Das Problem bei diesem Ansatz ist, dass Kettle keine Sequenzen im Generic Database Adapter unterstützt. Um diese Lösung zu implementieren, müssten wir den generischen Datenbankadapter so erweitern, dass er Sequenzen unterstützt und außerdem so flexibel ist, dass er mit beiden Datenbanken funktioniert. Fazit Obwohl dies ein einfaches und weit verbreitetes Problem zu sein scheint, scheint es in Kettle keine gute Lösung zu geben. Die Suche geht weiter...

Verfasst von

Maarten Winkels

Contact

Let’s discuss how we can support your journey.