> Inhalt: Einführung in das Programmieren mit Java > Datenbank-Ladeprogramm mit Graphischer Benutzeroberfläche (Java_Intro_02) |
|
Letzte
Bearbeitung dieses Dokuments: |
Voraussetzungen für das Verständnis dieses Dokuments:Grundkenntnisse in der Programmierung von Java (Klassen, Methoden, Schleifen) oder anderer Objekt-Orientierter Programmiersprachen (z.B. C++, Modula-2, Pascal). |
Ungefährer Zeitbedarf zum Durcharbeiten dieses Dokuments:Arbeitszeit:
|
Dieses
Dokument zeigt, wie die SQL-Kommandos aus einer sequentiellen Datei
gelesen werden und diese Kommandos an die Datenbank weitergeleitet
werden.
Zum Verfolgen des Fortschritts der Verarbeitung wird
vorgestellt, wie eine Klasse als parallel laufender 'Thread' (Prozeß)
entworfen wird.
Das 'parallele' Durchführen der Verarbeitung
bewirkt, daß die ausgeführten SQL-Kommandos und eventuelle
Fehlermeldungen sofort auf der Benutzeroberfläche (GUI)
angezeigt werden und nicht erst dann, wenn die Verarbeitung
abgeschlossen ist.
Vorigerer Schritt: XML-Struktur lesen
Vorbemerkung
und Funktion des Codes
Vorbedingungen
Klasse
DB_Load__Thread
eröffnen
Vorläufiger
Code in der Klasse DB_Load__Thread
Vorläufiger
zusätzlicher Code in der Klasse
DB_Load__ActionHandler
Zwischen-Test
Zusätzlicher
Code
* Import
in der Klasse DB_Load__Thread
* Globale
Variablen und 'Constructor' in der Klasse DB_Load__Thread
* Start
des Thread in der Methode processDBLoad(.
. .) /
Klasse DB_Load__ActionHandler
* Code
zum Einlesen der Datei mit den SQL-Kommandos / Klasse
DB_Load__Thread
* Code
für die Methode processDBOperation(.
. .) zum
Ausführen der SQL-Kommandos / Klasse DB_Load__Thread
Datei
mit den SQL-Kommandos erstellen
Gesamter
Code beim Ende dieses Schritts
* Klasse
DB_Load
* Klasse
DB_Load__ActionHandler
* Klasse
DB_Load__Thread
Test
Weitere
Schritte und verwandte Dokumentation
Die Einführung in die wichtigsten Felder als Basis für die Entwicklung kommerzieller Anwendungen mit Java ist jetzt abgeschlossen.
Nächster
Schritt: Meldungen drucken
Dieser
Schritt stellt eine einfache Möglichkeit für den Ausdruck
vor.
Seit der ersten Version dieses Dokuments wurde die
Möglichkeit zum Drucken in Java wesentlich verbessert –
Beispiele und Anleitung für die Möglichkeiten zum Drucken
ab Java Version 1.4 folgen demnächst.
Eine Anleitung, wie eine JAR- (Java-ARchiv-) Datei erstellt wird und wie das entwickelte Programm außerhalb von Eclipse ausgeführt wird, finden Sie im Schritt Packen in JAR-Datei .
In diesem Dokument wird der Code so erweitert, daß die gewählte Datei mit den SQL-Kommandos geöffnet wird, Zeile für Zeile (jede Zeile enthält ein SQL-Kommando) aus der Datei gelesen wird und das SQL-Kommando an das Datenbanksystem weitergeleitet wird.
Diese Verarbeitung geschieht in einem parallel laufenden Prozeß damit die ausgeführten SQL-Kommandos und eventuelle Fehlermeldungen sofort auf der Benutzeroberfläche (GUI) angezeigt werden können.
Schritt 4: XML-Struktur lesen ausgeführt – und dessen Vorbedingungen auch.
Das
Eröffnen der neuen Klasse wird nur in Stichworten und ohne
Abbildungen dokumentiert.
Wenn Sie sich unsicher sind, sehen Sie
bitte unter Datenbank-Ladeprogramm
mit Graphischer Benutzeroberfläche (Java_Intro_02) –
Einrichten von Project und Class >
Class
DB_Load eröffnen nach,
wie eine Klasse eröffnet wird.
Package:
js_intro02.client
Name:
DB_Load__Thread
[ ]
public static void main(String[] args) (nicht
markiert)
[ ]
Constructors from superclass (nicht
markiert)
[ ]
Inherited abstract methods (nicht
markiert)
Um schnell den Effekt eines parallel laufenden Prozesses zeigen zu können, wird zuerst ein einfacher Code implementiert der die Zahlen von 1 bis 20 mit einer Sekunde Pause dazwischen auf der GUI anzeigt.
Jetzt wird nur der Code mit den enthaltenen Kommentaren gelistet; die detaillierte Beschreibung erfolgt dann beim endgültigen Code für das Verarbeiten der SQL-Kommandos.
package
js_intro02.client;
/**
*
* @author kurt@javascout.biz
*
@date 2008-02-14
*
* @description
* Klasse
mit einem 'Thread', der die Datei mit den SQL-Kommandos
öffnet,
* diese Datei Zeile für Zeile
liest (jede Zeile enthält ein SQL-Kommando),
* diese
SQL-Kommandos an die Datenbank übergibt und
* das
SQL-Kommando und eventuelle Fehlermeldungen auf der GUI ausgibt.
*
* @change-log
*
when who why
*
--------------------------------------------------------
*
*/public
class
DB_Load__Thread
extends
Thread
{
/*
* Variable,
die auf die Klasse mit der GUI verweist.
* Damit kann
periodisch die jeweilige Zahl auf der GUI angezeigt werden.
*/
DB_Load
frmCallingFrame
;
/*
* 'Constructor'
der Klasse.
* Der als Parameter übergebene Wert
wird als 'final' definiert.
* Das bedeutet, daß
sich der Wert des Parameters nicht ändert während der
'Thread'
* ausgeführt wird und mit 'final' wird
die Performance verbessert. */
public
DB_Load__Thread(
final
DB_Load
parmCallingFrame) {
/*
* Der
als Parameter übergebene Wert wird in der Variablen dieser
Klasse gespeichert. */
frmCallingFrame
=
parmCallingFrame;
}
/*
* Die
Methode 'run' wird automatisch gestarted nachdem das Objekt
'konstruiert' wurde. */
public
void
run()
{
/*
* Eine
Klasse mit der Superklasse 'Thread' braucht eine
Fehlerbehandlung
* für den Fall, daß die
Ausführung von 'außen', d.h. durch die aufrufende
Methode,
* unterbrochen wurde. Deswegen die
try/catch-Logik. */
try
{
/*
* Vorläufiger
Code für die Klasse:
* Hochzählen von 1 bis
20 und anzeigen des Wertes auf der GUI
* mit 1 Sekunde
Pause dazwischen. */
for
(
int
i
= 0; i<= 20; i++) {
/* Anzeigen
der Zahl auf der GUI.
*/
frmCallingFrame
.get_txt_Report().append(
"Durchlauf
in DB_Load__Thread: "
+
Integer.toString(i) + "\n");
/* Eine
Sekunde warten bis die Schleife fortgesetzt wird.
*/
sleep(1000);
}
}
catch
(Exception
e) {
/*
* Unerwarteted
Ende des Threads; Fehlermeldung auf der GUI ausgeben.
*/
frmCallingFrame
.get_txt_Report().append(
"Unerwartetes
Ende von DB_Load__Thread: "
+
e.toString() + "\n");
}
}
}
Der
zusätzliche Code beschränkt sich darauf, in der Methode
processDBLoad(. . .)
ein Objekt der Klasse DB_Load__Thread
zu 'konstruieren' und zu 'starten'.
Nach dem Start läuft der
'Thread' parallel und die Methode processDBLoad(.
. .) wartet nicht auf das Ende von DB_Load__Thread.
/*
* Methode
die ausgeführt wird wenn die SQL-Kommandos aus der zuvor
ausgewählten Datei
* ausgeführt werden
sollen. */
private
static void
processDBLoad(DB_Load
parmCallingFrame) {
. . . . .
. . . . ./*
* Aufrufen
der Methode, in der die Parameter für die Verbindung zur
Datenbank ermittelt werden. */
conToDatabase
= processConnectToDatabase(parmCallingFrame,
array_DB_Parms);
/*
* Wenn
eine 'Connection zur Datenbank hergestellt werden konnte dann den
Thread
* für das Einlesen der Datei mit den
SQL-Kommandos und deren Ausführung starten. */
if
(conToDatabase
!=
null
)
{
DB_Load__Thread
t = new
DB_Load__Thread(parmCallingFrame);
t.start();
}
}
Bevor
der umfangreiche endgültige Code für das Einlesen und
Ausführen der SQL-Kommandos geschrieben wird, wird getestet, ob
die Klasse
DB_Load__Thread
wie
erwartet gestartet wird.
Dazu
wird – wie schon bekannt –
Run
> Run
ausgewählt.
Anschließend
wird mit der Schaltfläche
[ Auswahl
der SQL-Kommando-Datei ]
die
Datei mit den Parametern ausgewählt.
Nach dem Anklicken der Schaltfläche [ Start SQL-Kommandos ] werden zuerst die Parameter für die Verbindung zur Datenbank und anschließend das Ergebnis des vorläufigen Codes - die Zahlen 1 bis 20 - angezeigt. |
|
Bei der Klasse DB_Load__Thread muß der temporäre Code durch den endgültigen Code für das Öffnen und Lesen der sequentiellen Datei mit den SQL-Kommandos ersetzt werden.
Zum
leichteren Erkennen der geänderten oder zusätzlichen
Code-Teile sind diese fett geschrieben.
Es wird empfohlen, den
bestehenden Code Schritt für Schritt durch die nachfolgend
erklärten Code-Teile zu ersetzen.
package
js_intro02.client;
import
java.io.*;
import
java.sql.*;
/**
*
* @author kurt@javascout.biz
Für das Öffnen und Lesen der sequentiellen Datei und für die Ausführung der SQL-Kommandos gegen die Datenbank.
*
*/public
class
DB_Load__Thread
extends
Thread
{
/*
* Variable,
die auf die Klasse mit der GUI verweist.
* Damit kann
periodisch die jeweilige Zahl auf der GUI angezeigt werden.
*/
DB_Load
frmCallingFrame
;
/*
* Variable,
die auf die 'Connection' zum Datanbanksystem verweist.
*/
Connection
ConToDatabase
;
/*
* 'Constructor'
der Klasse.
* Der als Parameter übergebene Wert
wird als 'final' definiert.
* Das bedeutet, daß
sich der Wert des Parameters nicht ändert während der
'Thread'
* ausgeführt wird und mit 'final' wird
die Performance verbessert. */
public
DB_Load__Thread(
final
DB_Load
parmCallingFrame
,
final
Connection
parmConToDatabase
)
{
/*
* Die
als Parameter übergebenen Werte werden in den Variablen dieser
Klasse gespeichert. */
frmCallingFrame
=
parmCallingFrame;
ConToDatabase
=
parmConToDatabase;
}
Für die Verbindung zur Datenbank muß auch der 'Connector' beim 'Konstruieren' der Klasse als Parameter übergeben werden und als Variable der Klasse 'aufgehoben' werden.
/*
* Aufrufen
der Methode, in der die Parameter für die Verbindung zur
Datenbank ermittelt werden. */
conToDatabase
= processConnectToDatabase(parmCallingFrame,
array_DB_Parms);
/*
* Wenn
eine 'Connection zur Datenbank hergestellt werden konnte dann den
Thread
* für das Einlesen der Datei mit den
SQL-Kommandos und deren Ausführung starten. */
if
(conToDatabase
!=
null
)
{
DB_Load__Thread
t = new
DB_Load__Thread(parmCallingFrame
,
conToDatabase
);
t.start();
}
}
Neu
gegenüber dem temporären Code ist, daß auch der Wert
für die 'Connection' zur Datenbank übergeben werden
muß.
Das ist die einzige Änderung in der Klasse
DB_Load__ActionHandler
in
diesem Schritt.
/*
* Die
Methode 'run' wird automatisch gestarted nachdem das Objekt
'konstruiert' wurde. */
public
void
run()
{
/*
* Eine
Klasse mit der Superklasse 'Thread' braucht eine
Fehlerbehandlung
* für den Fall, daß die
Ausführung von 'außen', d.h. durch die aufrufende
Methode,
* unterbrochen wurde. Deswegen die
try/catch-Logik. */
try
{
/*
* Um
die Ausgabe auf der GUI klarer erkennbar zu machen wird ein
Trennstrich angezeigt.
*/
frmCallingFrame
.get_txt_Report().append(
"------------------\n"
);
/*
* Der
Name der Datei mit den SQL-Kommandos wird aus dem Feld der GUI
übernommen. */
String
strInputFileName =
frmCallingFrame
.get_txt_InputFile().getText();
/*
* Öffnen
der Datei; dazu werden Methoden vom package 'java.io' verwendet.
*/
LineNumberReader
InputStream =
new
LineNumberReader(
new
FileReader(strInputFileName));
/*
* Erste
Zeile der Datei wird gelesen. */
String
strLineRead = InputStream.readLine();
/*
* Wenn
die Datei leer ist wird gleich eine Fehlermeldung ausgegeben.
*/
if
(strLineRead
==
null
)
{
frmCallingFrame
.get_txt_Report().append(
"Eingabe-Datei
ist leer !\n"
);
}/*
* In
einer Schleife jede Zeile der Datei lesen und eine eigene Methode
aufrufen
* in der das SQL-Kommando gegen die Datenbank
ausgeführt wird.
* Die Schleife wird abgebrochen
wenn eine weitere Zeile nicht mehr gelesen werden kann.
*/
while
(strLineRead
!=
null
)
{
/* Gelesene
Zeile zur Kontrolle auf der GUI ausgegeben.
*/
frmCallingFrame
.get_txt_Report().append(
"Bearbeitete
Zeile aus der Datei: "
+
strLineRead +
"\n"
);
/*
* Ausführen
des SQL-Kommandos gegen die Datenbank erfolgt in einer
eigenen
* Methode.
* Grund dafür
ist, daß ein eigener try/catch Rahmen notwendig ist um bei
* einem fehlerhaften SQL-Kommando nicht in die
'catch'-Logik dieses try/catch Rahmens
* zu
kommen.
* Dann würde nämlich die Verarbeitung
abgebrochen und die weiteren SQL-Kommandos
* nicht
ausgeführt.
*/
processDBOperation(strLineRead);
/*
* Nächste
Zeile der Datei wird gelesen. */
strLineRead
= InputStream.readLine();
}
}
catch
(Exception
e) {
/*
* Unerwartetes
Ende des Threads; Fehlermeldung auf der GUI ausgeben.
*/
frmCallingFrame
.get_txt_Report().append(
"Unerwartetes
Ende von DB_Load__Thread: "
+
e.toString() + "\n");
}
}
Für
das Öffnen und Lesen einer sequentiellen Datei gibt es in Java
zahlreiche Möglichkeiten.
Der verwendete Code greift auf
Java-Funktionen für das Lesen von ganzen Zeilen aus einer
sequentiellen Datei mit Text zurück.
In einer while-Schleife wird dann Zeile für Zeile aus der Datei gelesen und innerhalb der Schleife wird dann die Methode processDBOperation(. . .) aufgerufen.
/*
* Methode,
die eine Zeile aus der Input-Datei als Parameter übernimmt,
* prüft
ob es nicht ein 'Kommentar' (Zeile beginnt mit '//') ist,
* das
SQL-Kommando an das Datenbanksystem übergibt
* und
anschließend eine Bestätigung oder eine Fehlermeldung auf
der GUI ausgibt. */
private
void
processDBOperation(String
parmstrSQLCommand) {
/*
* try/catch
Logik damit Fehler bei der Datenbank-Operation abgefangen werden
können. */
try
{
/*
* Prüfen
ob die im Paramater übergebene Zeile ein Kommentar ist.
* Eine
Kommentar-Zeile beginnt mit '//'. */
int
intCommentPosition
= parmstrSQLCommand.indexOf(
"//"
);
/*
* Wenn
die Zeile ein Kommentar ist wird die Verarbeitung in dieser Methode
beendet. */
if
((intCommentPosition
>= 0) && (intCommentPosition <= 1))
return
;
/*
* Die
im Parameter übergebene Zeile ist kein Kommentar;
* SQL-Operation auf der Datenbank ausführen.
*/
/*
* Zuerst ein 'Statement', das das SQL-Kommando
an die Datenbank weitergeben kann,
* 'konstruieren'.
*/
Statement
SQLStatement =
ConToDatabase
.createStatement();
/*
* Das
'Statement' ausführen; d.h. das SQL-Kommando an die Datenbank
übergeben.
*/
SQLStatement.executeUpdate(parmstrSQLCommand);
/*
* Wenn
der Code bis hierher gekommen ist, dann wurde das
SQL-Kommando
* ohne Fehler ausgeführt. Rückmeldung
auf der GUI ausgeben.
*/
frmCallingFrame
.get_txt_Report().append(
"SQL-Kommando
ausgeführt.\n"
);
}
catch
(SQLException
SQLExc) {
/*
* Beim
Ausführen des SQL-Kommandos ist ein Fehler
aufgetreten;
* Fehlermeldung auf der GUI ausgeben.
*/
frmCallingFrame
.get_txt_Report().append(
"Fehler
beim Ausführen des SQL-Kommandos: "
+
SQLExc.toString() +
"\n"
);
}
}
Wie
schon im Kommentar der Methode beschrieben, wurde das Ausführen
der SQL-Kommandos in einer eigenen Methode aus folgendem Grund
gewählt:
Das Erkennen von Fehlern bei der Ausführung von
SQL-Kommandos erfolgt in einem try/catch-Rahmen.
Ein Fehler in einem SQL-Kommando ist aber kein Grund, die weitere
Verarbeitung des Programms abzubrechen – das würde aber
passieren wenn das Ausführen der SQL-Kommandos innerhalb des
try/catch-Rahmens
in der Methode run()
erfolgen
würde.
Die Verarbeitung einer Zeile aus der eingelesenen Datei erfolgt in folgenden Schritten:
Zuerst
wird geprüft ob die Zeile nur ein Kommentar ist; das heißt
mit einem doppelten Schrägstrich ('//') beginnt./*
* Prüfen
ob die im Paramater übergebene Zeile ein Kommentar ist.
* Eine
Kommentar-Zeile beginnt mit '//'. */
int
intCommentPosition
= parmstrSQLCommand.indexOf(
"//"
);
/*
* Wenn
die Zeile ein Kommentar ist wird die Verarbeitung in dieser Methode
beendet. */
if
((intCommentPosition
>= 0) && (intCommentPosition <= 1))
return
;
Anschließend
muß von der Verbindung zur Datenbank (
conToDatabase
,
als Parameter beim Konstruieren der Klasse übergeben) ein
Objekt vom Typ
Statement
'geholt'
werden.
Das Statement
ist
eine Klasse aus der Java-Bibliothek (package)
java.sql
.
/*
* Zuerst
ein 'Statement', das das SQL-Kommando an die Datenbank weitergeben
kann,
* 'konstruieren'. */
Statement
SQLStatement =
ConToDatabase
.createStatement();
Mit
diesem
Statement
kann
das SQL-Kommando an das Datenbanksystem zur Ausführung
übergeben werden.
/*
* Das
'Statement' ausführen; d.h. das SQL-Kommando an die Datenbank
übergeben.
*/
SQLStatement.executeUpdate(parmstrSQLCommand);
Wenn
das übergebene SQL-Kommando einen Fehler enthält, wird der
catch()
-Teil
aufgerufen.
In diesem wird der Fehlertext extrahiert und der
Fehler auf der GUI angezeigt.
catch
(SQLException
SQLExc) {
/*
* Beim
Ausführen des SQL-Kommandos ist ein Fehler
aufgetreten;
* Fehlermeldung auf der GUI ausgeben.
*/
frmCallingFrame
.get_txt_Report().append(
"Fehler
beim Ausführen des SQL-Kommandos: "
+
SQLExc.toString() +
"\n"
);
}
Wie
detailliert die Fehlermeldung aussieht hängt vom
Datenbanksystem ab.
Per Definition muß die Datei mit den SQL-Kommandos im selben Verzeichnis erstellt werden wie die Datei mit der XML-Struktur mit den Parametern für die Verbindung zum Datenbanksystem (siehe Datenbank-Ladeprogramm mit Graphischer Benutzeroberfläche (Java_Intro_02 – XML-Struktur lesen > Verzeichnis und Datei mit der XML-Struktur erstellen).
|
|
|
|
Die
gerade erstellte Datei wird mit folgenden SQL-Kommandos gefüllt.
drop
table LANGUAGE;
create table LANGUAGE (IsoCode char(2) primary key
not null);
alter table LANGUAGE add column LongName
varchar(62);
alter table LANGUAGE add column SpokenBy
bigint;
insert into LANGUAGE values ('de', 'Deutsch',
100000000);
insert into LANGUAGE values ('en', 'Englisch',
1000000000);
insert into LANGUAGE values ('zh', 'Chinesisch',
1300000000);
Die SQL-Kommandos erstellen eine Datenbank-Tabelle, in der für verschiedene Sprachen der ISO-Code, der Name der Sprache und die Zahl der Menschen, die diese Sprache spricht, gespeichert werden kann.
Der
Code dieser Klasse wurde in diesem Schritt nicht verändert.
Für
eine Liste des gesamten Codes folgen Sie bitte dem Link zu Tutorial:
Datenbank-Ladeprogramm mit Graphischer Benutzeroberfläche
(Java_Intro_02) - ActionHandler > Gesamter Code am Ende diesen
Schrittes.
package
js_intro02.client;
import
java.awt.*;
import
java.awt.event.*;
import
java.io.*;
import
java.sql.*;
import
org.jdom.*;
import
org.jdom.input.*;
/**
*
* @author kurt@javascout.biz
*
@date 2008-02-07
*
* @description
* Klasse
mit statischen Methoden die ausgeführt werden wenn ein
'event'
* (z.B. der Klick einer Maustaste)
aufgetreten ist.
* Detail-Dokumentation finden
Sie bei den einzelnen Methoden.
*
* @change-log
*
when who why
*
--------------------------------------------------------
*
*/public
class
DB_Load__ActionHandler
{
/*
* Methode
die ermittelt, bei welchem GUI-Element ein 'ActionEvent' ausgelöst
wurde
* und die entsprechende Methode aufruft.
*/
public
static void
handleEvent(DB_Load
parmCallingFrame, ActionEvent parmActionEvent) {
/* Zuerst
wird die 'Identifikation' des GUI-Element aus dem ActionEvent
extrahiert. */
String
cmd = parmActionEvent.getActionCommand().trim();
/* Je
nach Auslöser des Events wird die entsprechende Methode
aufgerufen. */
if
(cmd.equals(
"btn_Select"
))
processSelectFile(parmCallingFrame);
if
(cmd.equals(
"btn_Start"
))
processDBLoad(parmCallingFrame);
}
/*
* Methode
die ausgeführt wird wenn die Datei mit den SQL-Kommandos
ausgewählt werden soll. */
public
static void
processSelectFile(DB_Load
parmCallingFrame) {
/*
* Fenster
für den 'File-dialog' aufrufen;
* in diesem kann
der Benutzer eine Datei auswählen. */
FileDialog
fd = new
FileDialog(parmCallingFrame,
"Bitte
wählen Sie die Datei mit den
SQL-Kommandos"
,
FileDialog.LOAD
);
/*
* Anfangswerte
für Verzeichnis und Dateiname setzen und Fenster sichtbar
machen.
*/
fd.setFile(
""
);
fd.setDirectory(
""
);
fd.setVisible(
true
);
/*
* Name
für gewähltes Verzeichnis und Datei aus dem 'File-dialog'
holen
* und einen String bilden. */
String
strDirectoryAndFileName = fd.getDirectory() +
fd.getFile();
/*
* Verzeichnis
und Datei-Name im entsprechenden Feld anzeigen.
*/
parmCallingFrame.get_txt_InputFile().setText(strDirectoryAndFileName);
}
/*
* Methode
die ausgeführt wird wenn die SQL-Kommandos aus der zuvor
ausgewählten Datei
* ausgeführt werden
sollen. */
private
static void
processDBLoad(DB_Load
parmCallingFrame) {
/*
* Damit
diese Methode nicht überladen wird, werden eigene Methoden
* für das Ermitteln der Paramater für
die Verbindung zur Datenbank,
* für das Aufbauen
der Verbindung zur Datenbank und
* für das
Ausführen der SQL-Kommandos
* aufgerufen.
*/
/*
* Die Übergabe der Parameter für
die Verbindung zur Datenbank erfolgt durch
* ein
String-Array. */
String[]
array_DB_Parms;
/*
* Aufrufen
der Methode, in der die Parameter für die Verbindung zur
Datenbank ermittelt werden. */
array_DB_Parms
= processGetDBParms(parmCallingFrame);
/*
* Prüfen,
ob alle DB-Parameter ermittelt werden konnten;
* bei
fehlenden Werten wird ein Array ohne Elemente zurückgeliefert.
* In
diesem Fall wird die Methode beendet; es erfolgt keine weitere
Verarbeitung. */
if
(array_DB_Parms.
length
<=
0)
return
;
/*
* Die
Verbindung (connection) zum Datenbanksystem wird in einer eigenen
Methode eröffnet.
* Die folgende Variable wird zum
Prüfen, ob der Aufbau der Verbindung erfolgreich war, und
* zur
Weitergabe an die Methode, in der die SQL-Kommandos ausgeführt
werden, verwendet. */
Connection
conToDatabase =
null
;
/*
* Aufrufen
der Methode, in der die Parameter für die Verbindung zur
Datenbank ermittelt werden. */
conToDatabase
= processConnectToDatabase(parmCallingFrame,
array_DB_Parms);
/*
* Wenn
eine 'Connection zur Datenbank hergestellt werden konnte dann den
Thread
* für das Einlesen der Datei mit den
SQL-Kommandos und deren Ausführung starten. */
if
(conToDatabase
!=
null
)
{
DB_Load__Thread
t = new
DB_Load__Thread(parmCallingFrame,
conToDatabase);
t.start();
}
}
/*
* Methode
die aus der Datei mit der XML-Struktur die Parameter für die
Verbindung
* zur Datenbank ausliest.
* Die
Parameter werden im String-Array an die aufrufende Methode
zurückgerufen */
private
static
String[]
processGetDBParms(DB_Load parmCallingFrame) {
/*
* Die
Übergabe der Parameter für die Verbindung zur Datenbank
erfolgt durch
* ein String-Array. */
String[]
array_DB_Parms =
new
String[4];
/*
* Extrahieren
des Verzeichnis-Namens aus dem im Text-Feld enthaltenen
* String
mit Verzeichnis und Datei-Namen für die Datei mit den
SQL-Kommandos. */
String
strDirectoryName =
parmCallingFrame.get_txt_InputFile().getText();
/*
* Trennen
von Verzeichnis und Datei durch den System-spezifischen
'file-separator'. */
String
strDirectorySeparator = System.getProperty(
"file.separator"
);
/*
* Postion
des letzten 'file-separator' in der Zeichenkette ermitteln.
*/
int
intLastDirectorySeparator
= strDirectoryName.lastIndexOf(strDirectorySeparator);
/*
* Wenn
kein 'file-separator' vorhanden ist dann kann die Zeichenkette
nicht
* 'sinnvoll' sein: In diesem Fall Fehlermeldung
im Report-Bereich der GUI ausgeben. */
if
(intLastDirectorySeparator
<= 0)
{
parmCallingFrame.get_txt_Report().append(
"Ungültiger
Verzeichnis-/Datei-Name: "
+
strDirectoryName +
"\n"
);
/* Zum
Zeichen eines Fehlers ein leeres Array zurückliefern.
*/
return
new
String[0];
}
/*
* Extrahieren
des Teiles mit dem Verzeichnis. */
strDirectoryName
= strDirectoryName.substring(0, intLastDirectorySeparator + 1);
/*
* 'Bauen'
der Zeichenkette mit Verzeichnis- und Datei-Name für die
Datei
* mit der XML-Struktur, die die Parameter
enthält. */
strDirectoryName
+=
"DB_Connection.xml"
;
/*
* Kompletten
String zur Kontrolle im Report-Bereich der GUI ausgeben.
*/
parmCallingFrame.get_txt_Report().append(
"Datei
mit den Datenbank-Parametern: "
+
strDirectoryName +
"\n"
);
/*
* XML-Element,
daß den 'Einstieg' in die hierarchische XML-Struktur
ermöglicht. */
Element
XML_RootElement;
/*
* Öffnen
der Datei mit der XML-Struktur.
* Die Klassen und
Methoden sind im package org.jdom.input enthalten. */
try
{
/* Damit
das Öffnen auch mit Windows-Betriebssystemen funktioniert,
* muß an den SAXBuilder eine 'file' übergeben
werden. */
File
f =
new
File(strDirectoryName);
/* Die
Klasse SAXBuilder ermöglicht ein einfaches Bearbeiten einer
Datei
* mit einer XML-Struktur, die dem
Document-Object_Model (DOM) entspricht. */
SAXBuilder
parser =
new
SAXBuilder();
/* Das
'document' enthält dann die gesamte XML-Struktur aus der Datei.
*/
Document
document = parser.build(f);
/* Das
Einstiegselement der XML-Struktur wird 'ergriffen'.
*/
XML_RootElement
= document.getRootElement();
}
catch
(JDOMException
e) {
/*
* Fehler:
Datei enthält keine XML-Struktur entsprechend dem
DOM.
* Meldung im Report-Bereich der GUI ausgeben.
*/
parmCallingFrame.get_txt_Report().append(
"'Not
well formed exception' beim Öffnen der Datei: "
+
strDirectoryName
+ "\n"
);
/* Zum
Zeichen eines Fehlers ein leeres Array zurückliefern.
*/
return
new
String[0];
}
catch
(Exception
e) {
/*
* Anderer
Fehler beim Versuch, die Datei mit der XML-Struktur zu
öffnen.
* Meldung im Report-Bereich der GUI
ausgeben.
*/
parmCallingFrame.get_txt_Report().append(
"Anderer
Fehler (als XML-Problem) beim Öffnen der Datei: "
+
strDirectoryName
+ "\n"
);
/* Zum
Zeichen eines Fehlers ein leeres Array zurückliefern.
*/
return
new
String[0];
}/*
* Die
verwendete XML-Struktur ist sehr einfach weil alle XML-Elemente mit
den Parametern
* direkt 'unter' dem 'root'-Element
angeordnet sind. */
/*
* Methoden des
packagage 'org.jdom.*' extrahieren die Werte der einzelnen
XML-Einträge
* wenn der Name des XML-Eintrags
angegeben wird. */
/*
* Zur Vereinfachung wird
nur eine Variable für alle XML-Einträge verwendet.
*/
Element
elementSingleParm;
/*
* Extrahieren
des Namens der Datei mit der Klasse, die die Verbindung zum
Datenbanksystem
* herstellt. */
elementSingleParm
= XML_RootElement.getChild("DataBaseDriverName"
);
if
(elementSingleParm
== null) {
/* XML-Eintrag
mit Namen 'DataBaseDriverName' nicht gefunden.
* Fehler
im Report-Bereich der GUI ausgeben und zum Zeichen eines
Fehlers
* ein leeres String-Array an die aufrufende
Methode zurückliefern.
*/
parmCallingFrame.get_txt_Report().append(
"XML-Eintrag
'DataBaseDriverName' nicht vorhanden.\n"
);
return
new
String[0];
}
/*
* Wert
des XML-Eintrages in den vorgesehenen String des String-Arrays
übernehmen. */
array_DB_Parms[0]
= elementSingleParm.getTextTrim();;
/* Zur
Kontrolle des Programm-Fortschrittes den Wert im Report-Bereich der
GUI anzeigen.
*/
parmCallingFrame.get_txt_Report().append(
"DataBaseDriverName:
"
+
array_DB_Parms[0] +
"\n"
);
/*
* Extrahieren
des Namens der Datenbank inklusive der spezifizierenden Zeichen.
*/
elementSingleParm
= XML_RootElement.getChild("DataBaseName"
);
if
(elementSingleParm
== null) {
/* XML-Eintrag
mit Namen 'DataBaseName' nicht gefunden.
* Fehler im
Report-Bereich der GUI ausgeben und zum Zeichen eines Fehlers
* ein
leeres String-Array an die aufrufende Methode zurückliefern.
*/
parmCallingFrame.get_txt_Report().append(
"XML-Eintrag
'DataBaseName' nicht vorhanden.\n"
);
return
new
String[0];
}
/*
* Wert
des XML-Eintrages in den vorgesehenen String des String-Arrays
übernehmen. */
array_DB_Parms[1]
= elementSingleParm.getTextTrim();;
/* Zur
Kontrolle des Programm-Fortschrittes den Wert im Report-Bereich der
GUI anzeigen.
*/
parmCallingFrame.get_txt_Report().append(
"DataBaseName:
"
+
array_DB_Parms[1] +
"\n"
);
/*
* Extrahieren
des Benutzer-Namens für den Datenbank-Zugriff.
*/
elementSingleParm
= XML_RootElement.getChild("DataBaseUserID"
);
if
(elementSingleParm
== null) {
/* XML-Eintrag
mit Namen 'DataBaseUserID' nicht gefunden.
* Fehler im
Report-Bereich der GUI ausgeben und zum Zeichen eines Fehlers
* ein
leeres String-Array an die aufrufende Methode zurückliefern.
*/
parmCallingFrame.get_txt_Report().append(
"XML-Eintrag
'DataBaseUserID' nicht vorhanden.\n"
);
return
new
String[0];
}
/*
* Wert
des XML-Eintrages in den vorgesehenen String des String-Arrays
übernehmen. */
array_DB_Parms[2]
= elementSingleParm.getTextTrim();;
/* Zur
Kontrolle des Programm-Fortschrittes den Wert im Report-Bereich der
GUI anzeigen.
*/
parmCallingFrame.get_txt_Report().append(
"DataBaseUserID:
"
+
array_DB_Parms[2] +
"\n"
);
/*
* Extrahieren
des Passworts für den Datenbank-Zugriff.
*/
elementSingleParm
= XML_RootElement.getChild("DataBasePassword"
);
if
(elementSingleParm
== null) {
/* XML-Eintrag
mit Namen 'Password' nicht gefunden.
* Fehler im
Report-Bereich der GUI ausgeben und zum Zeichen eines Fehlers
* ein
leeres String-Array an die aufrufende Methode zurückliefern.
*/
parmCallingFrame.get_txt_Report().append(
"XML-Eintrag
'DataBasePassword' nicht vorhanden.\n"
);
return
new
String[0];
}
/*
* Wert
des XML-Eintrages in den vorgesehenen String des String-Arrays
übernehmen. */
array_DB_Parms[3]
= elementSingleParm.getTextTrim();;
/* Zur
Kontrolle des Programm-Fortschrittes den Wert im Report-Bereich der
GUI anzeigen.
*/
parmCallingFrame.get_txt_Report().append(
"DataBasePassword:
"
+
array_DB_Parms[3] +
"\n"
);
/*
* Zurückliefern
des String-Arrays mit den Parametern. */
return
array_DB_Parms;
}
/*
* Methode,
die die Verbindung (connection) zur Datenbank herstellt.
* Die
'connection' wird von der Methode zurückgeliefert. */
private
static
Connection
processConnectToDatabase(
DB_Load
parmCallingFrame, String[] parmArray_DB_Parms) {/*
* Variable,
die von der Methode zurückgeliefert wird. */
Connection
conToDatabase = null
;
/*
*/
try
{
/*
* Klasse
für die Verbindung zum Datenbanksystem 'konstruieren'.
* Diese
Klasse wird vom Hersteller des Datenbanksystems mitgeliefert und
kann
* deswegen nicht statisch im Code definiert
werden.
* Für dieses Beispiel wurde der Name der
Klasse über die Parameter in der
XML-Struktur
* eingelesen.
* Die
Bibliotheks-Datei (*.jar) muß beim Start des Programms in der
Liste der *.jar-Datein
* enthalten sein.
* Das
Konstruieren der Klasse erfolgt mit der Java-Klasse 'Class'.
*/
Class.forName(parmArray_DB_Parms[0]);
/*
* Als
Konvention (für Java festgelegt) heißt die 'konstruierte'
Klasse für die Verbindung
* zum Datenbanksystem
'DriverManager'.
* Das erfolgreiche 'Konstruieren'
wird auf der GUI gemeldet.
*/
parmCallingFrame.get_txt_Report().append(
"'DriverManager'
konstruiert für: "
+
parmArray_DB_Parms[0] +
"\n"
);
/*
* Der
'DriverManager' enhält eine Methode mit der die Verbindung zu
einer Datenbank
* des Datenbanksystems erstellt werden
kann.
* Dazu muß der Name der Datenbank, ein
berechtigter Benutzer und dessen Passwort
* an die
Methode als Parameter übergeben werden. */
conToDatabase
= DriverManager.getConnection(
parmArray_DB_Parms[1],
parmArray_DB_Parms[2], parmArray_DB_Parms[3]);
/*
* Das
erfolgreiche Verbinden zu Datenbank wird auf der GUI gemeldet.
*/
parmCallingFrame.get_txt_Report().append(
"Verbindung
erfolgreich zur Datenbank: "
+
parmArray_DB_Parms[1] +
"\n"
);
/*
* Zur
Vereinfachung der Verarbeitung 'darf' das Datenbanksystem entscheiden
wann
* ein 'Commit' ausgeführt wird.
* Diese
Einstellung wird für das Tutorial gewählt um eventuelle
Fehler durch ein
* vergessenes 'Commit' zu
vermeiden.
* Für reale Entwicklungen soll diese
Einstellung nicht verwendet werden
* weil im
'Echtbetrieb' ein 'Commit' oder 'Rollback' so gesetzt werden muß,
* daß die Integrität der Daten gewahrt
bleibt - auch wenn ein Fehler auftritt.
*/
conToDatabase.setAutoCommit(
true
);
}
catch
(Exception
Exc) {
/*
* Verbinden
zur Datenbank war nicht erfolgreich;
* Fehler auf der
GUI melden und den zurückgelieferten Wert auf 'null'
setzen
* als Zeichen, daß das Programm
abgebrochen werden muß.
*/
parmCallingFrame.get_txt_Report().append(
"Fehler
beim Verbinden zur Datenbank: "
+
Exc.toString() +
"\n"
);
conToDatabase
= null
;
}
/*
* Erstellte
Verbindung zur Datenbank an die aufrufende Methode zurückliefern.
*/
return
conToDatabase;
}
}
package
js_intro02.client;
import
java.io.*;
import
java.sql.*;
/**
*
* @author kurt@javascout.biz
*
@date 2008-02-14
*
* @description
* Klasse
mit einem 'Thread', der die Datei mit den SQL-Kommandos
öffnet,
* diese Datei Zeile für Zeile
liest (jede Zeile enthält ein SQL-Kommando),
* diese
SQL-Kommandos an die Datenbank übergibt und
* das
SQL-Kommando und eventuelle Fehlermeldungen auf der GUI ausgibt.
*
* @change-log
*
when who why
*
--------------------------------------------------------
*
*/public
class
DB_Load__Thread
extends
Thread
{
/*
* Variable,
die auf die Klasse mit der GUI verweist.
* Damit kann
periodisch die jeweilige Zahl auf der GUI angezeigt werden.
*/
DB_Load
frmCallingFrame
;
/*
* Variable,
die auf die 'Connection' zum Datanbanksystem verweist.
*/
Connection
ConToDatabase
;
/*
* 'Constructor'
der Klasse.
* Der als Parameter übergebene Wert
wird als 'final' definiert.
* Das bedeutet, daß
sich der Wert des Parameters nicht ändert während der
'Thread'
* ausgeführt wird und mit 'final' wird
die Performance verbessert. */
public
DB_Load__Thread(
final
DB_Load
parmCallingFrame,
final
Connection
parmConToDatabase) {
/*
* Die
als Parameter übergebenen Werte werden in den Variablen dieser
Klasse gespeichert. */
frmCallingFrame
=
parmCallingFrame;
ConToDatabase
=
parmConToDatabase;
}
/*
* Die
Methode 'run' wird automatisch gestarted nachdem das Objekt
'konstruiert' wurde. */
public
void
run()
{
/*
* Eine
Klasse mit der Superklasse 'Thread' braucht eine
Fehlerbehandlung
* für den Fall, daß die
Ausführung von 'außen', d.h. durch die aufrufende
Methode,
* unterbrochen wurde. Deswegen die
try/catch-Logik. */
try
{
/*
* Um
die Ausgabe auf der GUI klarer erkennbar zu machen wird ein
Trennstrich angezeigt.
*/
frmCallingFrame
.get_txt_Report().append(
"------------------\n"
);
/*
* Der
Name der Datei mit den SQL-Kommandos wird aus dem Feld der GUI
übernommen. */
String
strInputFileName =
frmCallingFrame
.get_txt_InputFile().getText();
/*
* Öffnen
der Datei; dazu werden Methoden vom package 'java.io' verwendet.
*/
LineNumberReader
InputStream =
new
LineNumberReader(
new
FileReader(strInputFileName));
/*
* Erste
Zeile der Datei wird gelesen. */
String
strLineRead = InputStream.readLine();
/*
* Wenn
die Datei leer ist wird gleich eine Fehlermeldung ausgegeben.
*/
if
(strLineRead
==
null
)
{
frmCallingFrame
.get_txt_Report().append(
"Eingabe-Datei
ist leer !\n"
);
}/*
* In
einer Schleife jede Zeile der Datei lesen und eine eigene Methode
aufrufen
* in der das SQL-Kommando gegen die Datenbank
ausgeführt wird.
* Die Schleife wird abgebrochen
wenn eine weitere Zeile nicht mehr gelesen werden kann.
*/
while
(strLineRead
!=
null
)
{
/* Gelesene
Zeile zur Kontrolle auf der GUI ausgegeben.
*/
frmCallingFrame
.get_txt_Report().append(
"Bearbeitete
Zeile aus der Datei: "
+
strLineRead +
"\n"
);
/*
* Ausführen
des SQL-Kommandos gegen die Datenbank erfolgt in einer
eigenen
* Methode.
* Grund dafür
ist, daß ein eigener try/catch Rahmen notwendig ist um bei
* einem fehlerhaften SQL-Kommando nicht in die
'catch'-Logik dieses try/catch Rahmens
* zu
kommen.
* Dann würde nämlich die Verarbeitung
abgebrochen und die weiteren SQL-Kommandos
* nicht
ausgeführt.
*/
processDBOperation(strLineRead);
/*
* Nächste
Zeile der Datei wird gelesen. */
strLineRead
= InputStream.readLine();
}
}
catch
(Exception
e) {
/*
* Unerwartetes
Ende des Threads; Fehlermeldung auf der GUI ausgeben.
*/
frmCallingFrame
.get_txt_Report().append(
"Unerwartetes
Ende von DB_Load__Thread: "
+
e.toString() + "\n");
}
}
/*
* Methode,
die eine Zeile aus der Input-Datei als Parameter übernimmt,
* prüft
ob es nicht ein 'Kommentar' (Zeile beginnt mit '//') ist,
* das
SQL-Kommando an das Datenbanksystem übergibt
* und
anschließend eine Bestätigung oder eine Fehlermeldung auf
der GUI ausgibt. */
private
void
processDBOperation(String
parmstrSQLCommand) {
/*
* try/catch
Logik damit Fehler bei der Datenbank-Operation abgefangen werden
können. */
try
{
/*
* Prüfen
ob die im Paramater übergebene Zeile ein Kommentar ist.
* Eine
Kommentar-Zeile beginnt mit '//'. */
int
intCommentPosition
= parmstrSQLCommand.indexOf(
"//"
);
/*
* Wenn
die Zeile ein Kommentar ist wird die Verarbeitung in dieser Methode
beendet. */
if
((intCommentPosition
>= 0) && (intCommentPosition <= 1))
return
;
/*
* Die
im Parameter übergebene Zeile ist kein Kommentar;
* SQL-Operation auf der Datenbank ausführen.
*/
/*
* Zuerst ein 'Statement', das das SQL-Kommando
an die Datenbank weitergeben kann,
* 'konstruieren'.
*/
Statement
SQLStatement =
ConToDatabase
.createStatement();
/*
* Das
'Statement' ausführen; d.h. das SQL-Kommando an die Datenbank
übergeben.
*/
SQLStatement.executeUpdate(parmstrSQLCommand);
/*
* Wenn
der Code bis hierher gekommen ist, dann wurde das
SQL-Kommando
* ohne Fehler ausgeführt. Rückmeldung
auf der GUI ausgeben.
*/
frmCallingFrame
.get_txt_Report().append(
"SQL-Kommando
ausgeführt.\n"
);
}
catch
(SQLException
SQLExc) {
/*
* Beim
Ausführen des SQL-Kommandos ist ein Fehler
aufgetreten;
* Fehlermeldung auf der GUI ausgeben.
*/
frmCallingFrame
.get_txt_Report().append(
"Fehler
beim Ausführen des SQL-Kommandos: "
+
SQLExc.toString() +
"\n"
);
}
} }
Der
Code für das Programm kann jetzt durch Auswahl von
Run>Run
ausgeführt
werden.
Nach dem Anklicken der Schaltfläche [ Auswahl der SQL-Kommando-Datei ] erscheint der Dialog für die Auswahl der Datei. Wählen Sie die Datei 'SQL_Kommandos.txt' im Verzeichnis 'DB_Input' und Bestätigen Sie die Auswahl durch Anklicken der Schaltfläche [ OK ]. |
|
Nach dem Anklicken der Schaltfläche [ Start SQL-Kommandos ] werden die SQL-Kommandos von der gewählten Datei eingelesen, an das Datenbanksystem weitergegeben und zur Kontrolle auf der GUI angezeigt. |
|
Zur
Kontrolle muß der MySQL-Datenbank-Monitor über die
Kommandozeile aufgerufen werden. Sie
werden anschließend um das Passwort gefragt; wenn Sie das
Beispiel aus dem Tutorial verwendet haben ist das
Passwort Im
anschließend erscheinenden MySQL-Datenbank-Monitor können
Sie den Inhalt der Tabelle 'LANGUAGE' mit folgendem SQL-Kommando
abfragen: Als Ergebnis sollten Sie den kompletten Inhalt der Tabelle sehen. |
|
Dokument |
Inhalt |
Im
nächsten Schritt des Tutorials wird eine einfache Möglichkeit
des Druckens vorgestellt. |
|
Wenn Sie wiederholen wollen, wie die Anwendung in eine Java-ARchiv- (JAR-) Datei gepackt wird und wie das Java-Programm außerhalb von Eclipse ausgeführt wird, finden Sie die Anleitung in diesem Dokument. |