Datenbank-API in Groovy verwenden
Dieser Beitrag zeigt, wie im
Groovy-Skript
in
Prozessen
Datenbankoperationen mit der Intrexx Datenbank-API implementiert werden.
Vorteile des Intrexx APIs
Das Intrexx-API verfügt über eine Vielzahl an nützlichen Funktionen, um das Arbeiten mit Datenbank-Operationen
in Intrexx zu erleichtern. So existiert z.B. eine Client-SQL-Funktion "DATAGROUP", die es erlaubt,
in SQL-Statements anstelle des Namens einer Datengruppe deren
GUID
anzugeben.
Beispiel
g_dbQuery.executeAndGetScalarValue(conn, "SELECT COUNT(LID) FROM DATAGROUP('DAF7CECF66481FCABE50E529828116EAFE906962')")
Statt des Tabellennamens wird hier DATAGROUP('GUID_DATENGRUPPE') eingesetzt.
Auf diese Weise können hartcodierte Datengruppennamen vermieden werden. Darüber hinaus wird eine
korrekte Funktionsweise auch dann sichergestellt, wenn Applikationen und Prozesse mehrfach
importiert
werden, da bei einem Mehrfachimport innerhalb von Intrexx vorkommende GUIDs ersetzt werden.
Ein Ersetzen von Namen ist jedoch nicht möglich.
Ein weiterer Vorteil der Verwendung des APIs von Intrexx ist es, dass im Vergleich zum
Standard Java- oder Groovy-API weniger Code benötigt wird, um Datenbankabfragen und -operationen
in Intrexx zu realisieren.
Beispiel
def iMax = g_dbQuery.executeAndGetScalarValue(g_dbConnections.systemConnection, "SELECT MAX(LID) FROM DATAGROUP('DAF7CECF66481FCABE50E529828116EAFE906962')", 0 )
Mit Hilfe dieser einen Zeile ist es möglich, den Maximalwert der ID einer Tabelle zu bestimmen
und gleichzeitig mit dem Parameter 0 einen Fallbackvalue anzugeben, für den Fall, dass kein
Datensatz gefunden wurde und somit "null" als Ergebnis zurückkommt.
Groovy-Skripts erhalten durch die Verwendung des Intrexx Datenbank-API eine höhere Robustheit.
Beispielsweise resultieren Überläufe von Zahlenbereichen in einer ArithmeticException
anstatt in einer neuen, unvorhersehbaren Wertzuweisung an die Variable. Außerdem befindet
man sich durch die Verwendung des Intrexx-API zu jedem Zeitpunkt im Intrexx-Umfeld
(z.B. bzgl. Transaktionssicherheit und Rechtemanagement).
Erzeugen und Schließen von Prepared Statements und Result Sets
Beim Erzeugen von Prepared Statements in Verbindung mit Schleifen sollte immer darauf geachtet werden,
die Statements vor der Schleife zu erzeugen, innerhalb der Schleife zu füllen und auszuführen
und anschließend außerhalb der Schleife wieder zu schließen. Auf diese Weise werden
Speicherüberläufe vermieden und eine höhere Performance wird erzielt.
Falsch
for (i in 1..1000)
{
def stmt = g_dbQuery.prepare(conn, "UPDATE DATAGROUP('DAF7CECF66481FCABE50E529828116EAFE906962') SET TEXT = ? WHERE LID = ?")
stmt.setString(1, "Nummer ${i}")
stmt.setInt(2, i)
stmt.executeUpdate()
stmt.close()
}
Richtig
def stmt = g_dbQuery.prepare(conn, "UPDATE DATAGROUP('DAF7CECF66481FCABE50E529828116EAFE906962') SET TEXT = ? WHERE LID = ?")
for (i in 1..1000)
{
stmt.setString(1, "Nummer ${i}")
stmt.setInt(2, i)
stmt.executeUpdate()
}
stmt.close()
Allgemein sollte darauf geachtet werden, den close()-Befehl so früh wie möglich aufzurufen.
Schließen Sie Statements oder Result Sets am besten immer, sobald diese abgearbeitet wurden
und nicht mehr benötigt werden und warten Sie damit nicht bis zum Ende des Skripts.
Es ist jedoch zu beachten, dass close() nur bei Prepared Statement und Result Set-Objekten
aufgerufen werden muss. Werden Closures wie beispielsweise
g_dbQuery.executeUpdate(conn, "UPDATE DATAGROUP('DAF7CECF66481FCABE50E529828116EAFE906962') SET TEXT = ? WHERE LID = ?")
{
setString(1, "Hello World")
setInt(2, 1)
}
eingesetzt, muss und kann kein close() aufgerufen werden, da man an dieser Stelle über
kein entsprechendes Objekt verfügt, das geschlossen werden müsste. In diesem Fall übernimmt
Intrexx die notwendige Ressourcenverwaltung und -freigabe.
Iterieren über Result Sets
Beim Iterieren über ein Result Set ist auf die korrekte Abarbeitung des Result Sets zu achten.
Darüber hinaus sollten typisierte Methoden wie getBooleanValue(index i) verwendet werden,
um den Datentyp der Rückgabe genau zu spezifizieren. Somit können datenbankspezifische Unterschiede
bei der Abbildung von Daten und den verwendeten Datentypen vermieden werden.
Folgender Code ist nicht korrekt und führt zu Fehlern während der Iteration:
rs.each {
def strVal1 = rs.getStringValue(1)
def iVal2 = rs.getIntValue(2)
def bVal3 = rs.getBooleanValue(3)
}
Stattdessen sollte eine der folgenden Varianten verwendet werden, um eine korrekte Iteration zu gewährleisten.
Beispiel: Direkte Verarbeitung des Result Sets
while(rs.next())
{
def strVal1 = rs.getStringValue(1)
def iVal2 = rs.getIntValue(2)
def bVal3 = rs.getBooleanValue(3)
}
Beispiel: Verarbeitung einzelner Zeilen eines Result Sets
rs.each {row ->
def strVal1 = row.getStringValue(1)
def iVal2 = row.getIntValue(2)
def bVal3 = row.getBooleanValue(3)
}