Jetzt lerne ich endlich

Werbung
Hans-Joachim Adam
Jetzt lerne ich endlich...
Dateien,
Datenbanken
und SQL
mit
Einführung
Informationstechnik
z:\_skripte\java datenbanken\adam skript db & java\dbundjava030310.doc
DATEIBEHANDLUNG..............................................................................................................3
Stream .................................................................................................................................3
Datei schreiben....................................................................................................................3
1: DateiSchreiber...................................................................................................4
Datei lesen...........................................................................................................................4
2: DateiLeser .........................................................................................................4
Texte im TextArea ..............................................................................................................5
3: TextArea............................................................................................................5
4: DateiSchreiberLeser..........................................................................................5
FileWriter, FileReader ........................................................................................................5
5: DateiEditor ........................................................................................................6
6: LogEditor ..........................................................................................................6
Texteingaben von der Konsole (Tastatur) verarbeiten........................................................6
7: Tastatur .............................................................................................................7
ZUGRIFF AUF EINE DATENBANK ......................................................................................8
ODBC .................................................................................................................................8
Eine DSN einrichten ...........................................................................................................9
VERBINDUNG VON JAVA ZU EINER DATENBANK .......................................................9
DATENBANK .............................................................................................................................10
Metadaten der Datenbank holen..........................................................................................10
Namen der Tabellen und deren Eigenschaften holen..........................................................12
TABELLE ....................................................................................................................................14
Datenwerte einer Tabelle ausgeben ....................................................................................14
Senden eines SQL-Strings an eine Tabelle .........................................................................14
Tabellenwerte lesen.............................................................................................................15
DATENZUGRIFF AUF ODBC-DATENBANKEN UNTER JAVA ......................................18
TYPKONVERTIERUNG...........................................................................................................19
z:\_skripte\java datenbanken\adam skript db & java\dbundjava030310.doc
2
Dateibehandlung
Stream
Ein Stream ist eine Konstruktion, welche die Fähigkeit besitzt, Daten auf ein erdachtes „Ausgabegerät“ zu
schreiben oder von diesem zu lesen. Man kann einen Stream auch als einen Kommunikationspfad zwischen
einer Quelle und einem Ziel beschreiben. In Java ist ein Stream ein Objekt, das mit einem bestimmten Ziel
oder einer bestimmten Quelle verbunden ist, zum Beispiel mit einer Datei oder mit einem anderen Rechner.
Ist ein Stream mit einem Ziel verbunden auf dem Daten abgelegt werden, so ist der Stream ein Ausgabestream. Und anders herum, ist ein Stream mit einer Quelle verbunden, von der Daten empfangen werden,
so ist er ein Eingabestream.
In Java gibt es zwei Arten von Streams. Zum Einen die Byte-Streams und zum Anderen die ZeichenkettenStreams. Der größte Unterschied der beiden Streams ist, dass die Transporteinheit der Byte-Streams 8 Bit
lange Bytes sind. Zeichenketten-Streams dagegen verwenden 16 Bit lange Unicode-Zeichen, um besser mit
Strings und Zeichentypen zusammenarbeiten zu können.
Die Byte-Streams werden in Java durch die beiden Klassen java.io.Inputstream (Eingabestream) und
java.io.outputstream (Ausgabestream) repräsentiert. Die Zeichenketten-Streams durch java.io.Reader (Eingabestream) und java.io.Writer (Ausgabestream).
Die wichtigsten Klassen in Verbindung mit Streams sind:
Writer
FileWriter
BufferedWriter
stringWriter
Reader
FileReader
BufferedReader
StringReader
OutputStream
FileOutputstream
BufferedOutputstream
DataOutputStream
InputStream
FileInputstream
BufferedInputstream
DataInputStream
Diese Klassen stellen Grundlagen für das Lesen bzw. Schreiben von Daten durch Streams bereit. Sie sind im
Paket java.io enthalten. Es ist empfehlenswert das gesamte java.io Paket in ein Programm zu importieren,
das Streams verwenden soll. Dies geschieht mit der Anweisung import java.io.*;
Datei schreiben
Die Datei-Ausgabe und -EinleseDateiSchreiber
FileOutputStream
Streams sind leicht zu handhaben.
Nach dem Erstellen des Streamoutput
Objekts ruft man die Methoden wriException
write
te() bzw. read() auf. Die Daten werclose
den nur Byteweise übertragen: aus
diesem Grund kann man beim Schreiben nicht den String direkt übergeben, sondern man muss die Methode getBytes() aufrufen, welche den
String Byteweise zurückliefert. Diese Rückgaben können von der write()-Methode des OutputStream direkt
verwertet werden. Falls der Schreibvorgang fehlschlägt (z.B. Verzeichnis nicht vorhanden, Diskette voll)
wirft die write()-Methode eine IOException, die man mit der try .. catch Konstruktion auswerten kann. Die
Verbindung zur Datei wird mit der Methode close() beendet.
import java.io.*;
class DateiSchreiber {
public static void main(String args[]) {
try{
String s = "Das ist ein FileOutputStream";
FileOutputStream output = new FileOutputStream("test.txt");
output.write(s.getBytes());
output.close();
System.out.println("Datei test.txt wurde erstellt");
}
catch (IOException e){
System.out.println("Schreiben fehlgeschlagen");
}
}
}
z:\_skripte\java datenbanken\adam skript db & java\dbundjava030310.doc
3
Dateibehandlung
Datei lesen
Die Methode write des OutputStream ruft immer wieder die ihm übergebenen Methode auf, bis dies das
„Ende-Zeichen“ zurück gibt. Die Methode getBytes des String-Objekts wiederum gibt bei jedem Aufruf ein
weiteres Zeichen des Strings aus.
Das Programmbeispiel erzeugt die Ausgabe wie rechts
dargestellt.
1:
DateiSchreiber
Erstellen Sie ein Programm zur Erzeugung
einer Textdatei wie im Beispiel oben. Die Erfolgreiche Speicherung können Sie mittels
des Windows-Notepad (oder Editor) überprüfen.
Wenn dem Stream-Objekt keine Pfadbezeichnung,
sondern nur der Dateiname übergeben wird, so
schreibt es die Datei in das Verzeichnis, in dem die
Klassendatei steht. Es ist möglich, relative und absolute Pfade und Laufwerkbuchstaben anzugeben. Achtung: anders als bei Windows üblich werden die Verzeichnisse nicht mit dem linken Schrägstrich (backslash
\), sondern mit einem rechten Schrägstrich (slash /) getrennt. Es sind also mögliche Pfadangaben:
FileOutputStream output = new FileOutputStream("../../dateiSchreiber/classes/test.txt");
FileOutputStream output = new FileOutputStream("/temp/test.txt");
FileOutputStream output = new FileOutputStream("c:/temp/test.txt");
Datei lesen
Dateien lesen kann man mittels eines
DateiLeser
FileInputStream
FileInputStreams. Die Methode read()
gibt je Aufruf ein weiteres Byte aus der
input
Datei zurück. Um die gesamte Datei
read
auszulesen, muss man daher die input()close
Methode in einer Schleife wiederholt
ausführen lassen. Auch die input()Methode wirft eine IOException. Die
Verbindung zur Datei wird ebenfalls mit der close()-Methode beendet.
Exception
byte b;
while ((b = (byte)input.read()) != -1) {
System.out.print((char)b);
}
2:
DateiLeser
Es ist ein Leseprogramm zu schreiben. Sie können auch in der while-Schleife die eingelesenen
Buchstaben in einem String s sammeln, und diesen am Schluss mit System.out.println(s); ausgeben.
4
Dateibehandlung
Texte im TextArea
Texte im TextArea
Texte können in Java mittels eines TextAreas angezeigt und bearbeitet
werden. Das TextArea stellt dazu die Methoden setText() und getText() zur
Verfügung.
TextArea ta1 = new TextArea();
...
String s;
s = ta1.getText();
ta2.setText(s);
3:
TextArea
Schreiben Sie ein Programm wie im Beispiel rechts, mit dem Sie
Text aus einem Textbereich in einen zweiten übertragen. Verändern Sie auch die Größe und das Aussehen des TextArea (z.B.
mit / ohne Scrollbalken)
4:
DateiSchreiberLeser
Die Texte sollen mittels TextAreas ausgegeben und eingelesen
werden. Auch hier können Sie die Arbeitsweise mittels des Windows-Notepad (oder Editor) überprüfen.
FileWriter, FileReader
Die Klassen FileWriter und FileReader ermöglichen ebenfalls das Schreiben und Lesen von Textdateien.
import java.io.*;
class DateiWriter {
public static void main(String args[]) {
try{
String s = "Das ist ein FileWriter";
FileWriter output = new FileWriter("test.txt");
output.write(s);
output.close();
System.out.println("Datei test.txt wurde erstellt");
}
catch (IOException e){
System.out.println("Schreiben fehlgeschlagen");
}
}
}
Dieses Beispiel unterscheidet sich nicht
sehr von den vorhergehenden Anwendungen, außer dass man sich die Funktion
getBytes() sparen konnte, weil die Klasse
FileWriter spezialisierter auf Strings ist als
die Klasse FileOutputStream.
Außerdem besitzt die Klasse FileWriter
noch einen weiteren Konstruktor, der wie
folgt aussieht: public FileWriter(String
Dateiname, boolean append); Der zusätzliche Parameter gibt an, ob der Inhalt einer
Datei, falls sie schon vorhanden ist, überschrieben werden soll oder die neuen Daten einfach hinten dran geschrieben werden
FileWriter
output
write
close
DateiEditor
ta1: TextArea
Exception
FileReader
input
read
close
Exception
5
Dateibehandlung
Texteingaben von der Konsole (Tastatur) verarbeiten
sollen. Man könnte also in Zeile 6 auch schreiben: new FileWriter("test.txt", true); so würde die Datei test.txt
bei jedem Programmaufruf um eine neue Zeile erweitert werden.
Die Klasse FileReader wird exakt gleich angewendet wie die Klasse FileInputStream: auch FileReader gibt
die Datei nur zeichenweise zurück. Beide Anwendungen unterscheiden sich demnach nur in den Vokabeln.
Der Dateiinhalt wird aber nicht direkt Zeichenweise auf dem Bildschirm ausgegeben, sondern die einzelnen
Zeichen müssen in einem String gesammelt werden. Das kann man mit s = s + (char)b; innerhalb einer
Schleife erreichen, wobei s der String und b das eingelesene Zeichen ist.
5:
DateiEditor
Erstellen Sie einen Mini-Editor: Im Textfeld oben kann
der Dateiname eingetragen werden.
Die Button unter dem Textbereich dienen zum Speichern bzw. Laden der Datei. Wenn sie nicht vorhanden
ist, wird sie beim Speichern angelegt, beim Ladeversuch einer nicht vorhandenen Datei gibt es eine Fehlermeldung.
Hier dient derselbe Textbereich sowohl zum Eintippen
des von Programm einzulesenden Textes als auch als
Ausgabebereich.
6:
LogEditor
In einem Logfile sollen auf Buttonklick Textzeilen angehängt werden. Ein Button soll die gesamte Log-Datei
ausgeben, ein weiterer Button soll die Logdatei leeren.
Texteingaben von der Konsole (Tastatur) verarbeiten
Das Programm readsystem demonstriert, wie man mit Hilfe von Streams Eingaben des Benutzers verarbeiten
kann. Das Programm tut nicht viel, aber zur Erläuterung des Problems, wie man Benutzereingaben verarbeitet, genügt es. Das Programm wartet eine Benutzereingabe ab und gibt diese dann wieder aus. Gibt man
allerdings quit ein wird das Programm beendet.
import java.io.*;
class Readsystem {
public static void main(String Arguments[]) throws IOException {
String zeile;
InputStreamReader input = new InputStreamReader(System.in);
BufferedReader buffer = new BufferedReader(input);
while ((zeile = buffer.readLine()) != null){
if (zeile.equals("quit")) {
input.close();
break;
}
else {
System.out.println(zeile);
}
}
}
}
6
Dateibehandlung
Texteingaben von der Konsole (Tastatur) verarbeiten
Die wichtigsten Zeilen sind:
InputStreamReader input = new InputStreamReader(System.in);
BufferedReader buffer = new BufferedReader(input);
in der ersten Zeile wird ein Eingabe-Stream-Objekt erstellt, der als Parameter das Objekt System.in erhält.
System.in repräsentiert die Eingaben der Konsole (wie System.out die Ausgaben repräsentiert). In der
zweiten Zeile entsteht ein Objekt eines BufferedReader, dem Speicherobjekt für die Tastatureingaben, die
von System.in geliefert werden.
System
InputStreamReader
BufferedReader
Readsystem
zeile: String
in
input
buffer
readLine
close
Beide Zeilen werden oft zu einer zusammengefasst, weil man praktisch nie auf die Objekte einzeln zugreifen
möchte. BufferedReader bekommt also nicht direkt ein Objekt übergeben, sondern eine Vorschrift, wie es
sich das entsprechende Objekt erzeugen kann. Aus diesen “Zwischenklassen” werden intern selbstverständlich Objekte erzeugt, aber wir bekommen sie nicht zu Gesicht. Deshalb bezeichnet man sie als anonyme
Klassen.
BufferedReader buffer = new BufferedReader(new InputStreamReader(System.in));
Tastatureingaben werden also von Java her ähnlich wie Textdateien gesehen. Auch hier geschieht das Lesen
mit Hilfe von Streams: Wir erzeugen eine Instanz des BufferedReader, welcher über einen InputStreamReader auf die Tastatur-Eingabe-Klasse (System.in) zugreift. System kann direkt verwendet werden, ohne dass
man erst ein Objekt erzeugen muss (abstrakte Klasse). Mit dem Attribut System.in stellt System ein Byte
Speicherplatz bereit, auf den man mit InputStreamReader zugreifen kann. BufferedReader wiederum kann
Bytes dieses Streams lesen, speichern und mit der Methode readLine() zeilenweise bereitstellen.
7:
Tastatur
Es sollen Tastatureingaben direkt zeilenweise in ein TextArea übernommen werden. Bestimmte
Steuerwörter (z.B. save, load, quit) sollen direkt ausgewertet und ausgeführt werden.
7
Zugriff auf eine Datenbank.
ODBC
Zugriff auf eine Datenbank
.
ODBC
Um Datenbanken von Java aus anzusprechen, muss der ODBC-Treiber installiert und konfiguriert werden.
Java greift nämlich mittels der JDBC-ODBC-Bridge über den ODBC-Treiber auf die Datenbank zu. Es gibt
auch noch firmenspezifische (native) Datenbanktreiber und „all-Java“-Treiber, die direkten Zugriff auf die
Datenbank ermöglichen. Diese werden hier aber nicht betrachtet.
Datenbank
(z.B. ACCESS)
ODBC-Treiber
JDBC-ODBC
Bridge
JDBC-Driver-Manager
XYZ-Datenbank
XYZ-Treiber
(firmenspezifisch)
}
}
Java-Pragramm
Man muss also zunächst den ODBC-Zugriff auf die Datenbank einrichten. Das geschieht mit Hilfe des
ODBC-Administrators. Mit diesem können Sie nicht nur die Verbindung zu bestehenden Datenbanken aufnehmen, sondern auch Datenbanken neu erzeugen.
Rufen Sie den ODBC-Administrator auf. Sie Erreichen den ODBC-Administrator über Start - Einstellungen
- Systemsteuerung - Verwaltung - Datenquellen (ODBC). Wem dieser Weg zu lang ist, kann sich auch die
Datei C:\WINNT\System32\ODBCAD32.exe in ein beliebiges Verzeichnis kopieren und/oder eine Verknüpfung darauf anlegen.
. Literatur: Roland Willms: Java Programmierung Praxisbuch, Franzis Verlag, Professional Series, ISBN 3-7723-7604-5
8
Verbindung von Java zu einer Datenbank
Eine DSN einrichten
Eine DSN einrichten
Sie müssen mit dem ODBC Administrator eine System-DSN einrichten um
auf ihre Datenbank zugreifen zu können. Das müssen Sie tun, wenn Sie die
Datenbank mit dem ODBC Administrator erstellen oder auf eine zuvor mit
ACCESS erstellte Datenbank zugreifen wollen.
Mittels dem Button Hinzufügen erstellen Sie einen neuen Aliasnamen für
die Datenbank. Wenn Sie auf eine
bereits
bestehende
(ACCESS)Datenbank zugreifen wollen, dann
klicken Sie den Button Konfigurieren
und wählen die gewünschte ACCESSDatenbank aus:
In diesem Beispiel ist die unter
ACCESS erstellte Datenbank ITC2000.mdb, die sich im Ordner
C:\Programme\Adam\SeQueL\ITC
befindet unter dem Alias-Namen ITC
ansprechbar.
Die Vergabe Aliasnamen bringt den
Vorteil, dass im Anwendungsprogramm nur die Alias-Namen erscheinen, und dieses daher nicht angepasst
werden muss, wenn man den Pfad zur
Datenbank ändert oder das System auf
einen anderen Rechner überträgt.
Verbindung von Java zu einer Datenbank
Es muss das Paket java.sql in den Programmcode importiert werden.
DriverManager
import java.sql.*;
Als erstes ist der Treiber zu laden. Wir wollen ODBC-konforme Datenbanken abfragen und müssen daher die JDBC-ODBC-Bridge laden:
getConnection
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
Danach muss die Verbindung zur Datenbank (mit dem Aliasnamen
ITC) aufgebaut werden. Dazu ist ein Objekt der Klasse Connection zu
erstellen. Dieses Objekt wird mit der Klassenmethode getConnection()
der Klasse DriverManager erzeugt. Vom DriverManager braucht man
kein Objekt zu erstellen! Dieses Connection-Objekt stellt die notwendigen Methoden zum Datentransport bereit.
Connection
createStatement
getMetaData
close
Exception
Connection con = DriverManager.getConnection
("jdbc:odbc:ITC");
9
Datenbank
Metadaten der Datenbank holen
Datenbank
Metadaten der Datenbank holen
Um die Daten aufnehmen zu können, muss in Java ein Objekt erstellt werden, welches den Speicherplatz für
die zu übertragenden Daten bereitstellt. Wir treffen hier auf das Problem, dass verschiedene Programme zusammenarbeiten müssen: die Datenbank stellt Daten bereit, unser Java-Programm muss diese lesen. Die Datenübertragung kann über Speicherbereiche erfolgen, auf die beide Anwendungen Zugriff haben. Die Frage
ist nun, wer diesen Speicherplatz zur Verfügung stellt: das könnte das Betriebssystem sein, oder eines der
beteiligten Objekte. Meist stellt das anfragende Objekt den Platz zur Verfügung, denn dann wird der Speicherplatz nur beansprucht, wenn auch tatsächlich Abfragen stattfinden sollen. Selbstverständlich kann dieser
Speicherplatz nicht beliebig sein, sondern er muss nach Größe und Art genau zur zu übertragenden Datenstruktur passen. In diesem Fall hier benötigen wir die Klasse DatabaseMetaData.
Zunächst wollen wir die Metadaten der Datenbank erfragen. DatabaseMetaData istwie auch Connection abstrakt deklariert, das bedeutet, dass wir den Speicherplatz direkt verwenden können, ohne erst ein Objekt der
Klasse DatabaseMetaData erstellen zu müssen. Wir können direkt mit der Methode getMetaData() der Connection die Daten übernehmen:
DatabaseMetaData dbmd = con.getMetaData();
Metadaten kann man nun direkt mit den entsprechenden Methoden
auslesen und beispielsweise in einem TextArea ausgeben:
text = "";
text += "Datenbank:
" +
dbmd.getDatabaseProductName() + "\n";
text += "Version:
" +
dbmd.getDatabaseProductVersion() + "\n";
area.setText(text);
DatabaseMetaData
getDatabaseProduktName(): String
getDatabaseProduktVersion(): String
Weitere Methoden können Sie der Java-Hilfe entnehmen.
Unser Programm ist so aber noch nicht ganz fertig. Beim Datenbankzugriff kann es zu vielerlei Fehlern
kommen: Datenbank ist nicht (mehr) vorhanden, Zugriff verweigert wegen fehlender Rechte usw. Deshalb
wird die Datenbankabfrage in ein try - catch Konstrukt eingepackt, welches Systemfehler abfängt.
try{
// hier stehen die Zugriffsbefehle
}
catch (Exception e){
area.setText(e.toString());
}
Hier nun ein vollständiges Programm, welches
das Fenster rechts erzeugt:
import java.awt.*;
import java.awt.event.*;
import java.sql.*;
class JavaDB extends Frame implements ActionListener{
Label lbdb = new Label("URL = jdbc:odbc:");
TextField url= new TextField("MS Datenbank",20);
Button execute = new Button("
Ausführen
");
TextArea area = new TextArea(10, 50);
Font courier = new Font("Courier",Font.PLAIN,12);
public JavaDB(){
addWindowListener(new WindowAdapter(){
public void windowClosing(WindowEvent e){
dispose();
10
Datenbank
Metadaten der Datenbank holen
System.exit(0);
}
});
setLayout(new FlowLayout());
add(lbdb);
add(url);
add(execute);
execute.addActionListener(this);
add(area);
area.setFont(courier);
}
public void actionPerformed(ActionEvent e){
if (e.getSource() == execute){
accessDatabase();
}
}
public void accessDatabase(){
try {
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
Connection con = DriverManager.getConnection ("jdbc:odbc:"+url.getText());
DatabaseMetaData dbmd = con.getMetaData();
display(dbmd);
}
catch (Exception e){
area.setText(e.toString());
}
}
public void display(DatabaseMetaData dbmd){
String text = "Metadaten der Datenbank"+"\n\n";
area.setText(text);
try{
text = "";
text += "Katalog:
" + dbmd.getCatalogTerm() + "\n";
text += "Datenbank:
" + dbmd.getDatabaseProductName() + "\n";
text += "Version:
" + dbmd.getDatabaseProductVersion() + "\n";
text += "Treibername: " + dbmd.getDriverName() + "\n";
text += "Version:
" + dbmd.getDriverVersion() + "\n";
text += "URL:
" + dbmd.getURL() + "\n";
text += "User:
" + dbmd.getUserName() ;
area.append(text);
}
catch (Exception e){
area.setText(e.toString());
}
}
public static void main(String args[]){
System.out.println("Starting JavaDB...");
JavaDB mainFrame = new JavaDB();
mainFrame.setSize(400, 250);
mainFrame.setTitle("JavaDB");
mainFrame.setVisible(true);
}
}
11
Datenbank
Namen der Tabellen und deren Eigenschaften holen
Namen der Tabellen und deren Eigenschaften holen
Das vorige Beispiel gibt nicht so sehr interessante Daten
preis. Um beispielsweise die Namen der in der Datenbank enthaltenen Tabellen zu erfahren muss man mit
einem weiteren Zwischenschritt diese aus den Metadaten
extrahieren. Das ist deshalb so kompliziert, weil man
nicht von vornherein sagen kann, wie viele Tabellen
vorkommen, und welche Felder diese enthalten. Daher
kann man nicht einfach einige Speicherplätze (Attribute)
in der Klasse DatabaseMetaData bereitstellen, sondern
man braucht Methoden, die in einer weiteren Klasse
definiert sind: in ResultSet.
DatabaseMetaData
getDatabaseProduktName(): String
getDatabaseProduktVersion(): String
...
getTables(): ResultSet
getColumns(): ResultSet
ResultSet
Das Auslesen der Tabellennamen geschieht mit Hilfe der
next
Exception
Klasse ResultSet. Auch von dieser Klasse braucht man
getString("TABLE_NAME");
keine Objekte abzuleiten. Mit Hilfe der Methode getTables() aus der DatabaseMetaData-Klasse sind die Tabellennamen mittels Methoden des ResultSet-Objekts
verfügbar. Rufen Sie die Online-Hilfe des Java-JDK auf um weitere Informationen über die folgenden ResultSet-Klasse und deren Methoden zu erhalten!
text = "";
String[] tableType = {"TABLE"};
//nur Benutzertabellen
ResultSet rsTab = dbmd.getTables(null,null,"%",tableType);
Der wiederholte Aufruf der Methode rsTab.getString("TABLE_NAME") gibt je Aufruf einen weiteren Tabellennamen aus. Wiederholtes Aufrufen einer Methode zum Auslesen eines unbekannt großen Speicherbereiches wird öfter angewendet. Je Aufruf wird ein weiteres Datenelement geliefert, oder ein „Schlusszeichen“, welches das aufrufende Programm auswerten kann*).
table = rsTab.getString("TABLE_NAME");
Der Aufruf wird in einer Schleife untergebracht:
while (rsTab.next()){
table = rsTab.getString("TABLE_NAME");
text = table + "\n";
area.append(text);
text = "";
}
Die Namen der Felder die in dieser Tabelle enthalten sind erhält man nach dem Erzeugen eines weiteren
ResultSet:
rsCol = dbmd.getColumns(null,null,table,"%");
Aus diesem ResultSet erhalten Sie nacheinander die einzelnen Feldnamen durch wiederholten Aufruf der
Methode rsCol.getString("COLUMN_NAME"). Entsprechend können auch die weiteren Eigenschaften der
Felderwie TYPE_NAME, DATA_TYPE, REMARKS usw. ermittelt werden.
text += rsCol.getString("COLUMN_NAME");
Die Aufrufe der einzelnen Tabellen und deren Feldnamen werden in ineinander geschachtelten Wiederholungsschleifen untergebracht. Die Methode next() gibt true zurück, solange noch weitere Elemente im ResultSet vorhanden sind. next() kann man daher als Wiederholungskriterium in einer while-Schleife verwenden.
while (rsTab.next()){
table = rsTab.getString("TABLE_NAME");
text = table + "\n";
area.append(text);
text = "";
*) Das ist uns schon mal im Kapitel „Streams, Auslesen eines TextArea in meinem Skript zur OO-Progrmmierung begegnet.
12
Datenbank
Namen der Tabellen und deren Eigenschaften holen
rsCol = dbmd.getColumns(null,null,table,"%");
while (rsCol.next()){
text += rsCol.getString("COLUMN_NAME") + " ";
text += rsCol.getString("TYPE_NAME")
+ " ";
text += rsCol.getString("DATA_TYPE")
+ " ";
text += rsCol.getString("REMARKS")
+ "\n";
}
area.append(text);
}
Ein vollständiges Programm kann mit einiger kosmetischer Korrektur bei der Ausgabe das folgende Bild
liefern. Sie sehen die Ausgabe der Tabellennamen und darunter in jeweils einer Zeile ein Datenfeld samt
Datentyp und Bemerkung.
Hier folgt noch der komplette Code des Programms:
import java.awt.*;
import java.awt.event.*;
import java.sql.*;
class JavaDBTabellen extends Frame implements ActionListener{
Label lbdb = new Label("URL = jdbc:odbc:");
TextField url= new TextField("MS Datenbank",20);
Button execute = new Button("
Ausführen
");
TextArea area = new TextArea(20, 70);
Font courier = new Font("Courier",Font.PLAIN,12);
public JavaDBTabellen(){
addWindowListener(new WindowAdapter(){
public void windowClosing(WindowEvent e){
dispose();
System.exit(0);
}
});
setLayout(new FlowLayout());
add(lbdb);
add(url);
add(execute);
execute.addActionListener(this);
add(area);
area.setFont(courier);
}
public void actionPerformed(ActionEvent e){
if (e.getSource() == execute){
accessDatabase();
}
}
public void accessDatabase(){
try {
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
Connection con = DriverManager.getConnection("jdbc:odbc:"+url.getText());
13
Tabelle
Datenwerte einer Tabelle ausgeben
DatabaseMetaData dbmd = con.getMetaData();
display(dbmd);
}
catch (Exception e){
area.setText(e.toString());
}
}
public void display(DatabaseMetaData dbmd){
String text = "";
try{
text = "Tabellen der Datenbank: " + dbmd.getURL() + "\n";
area.setText(text);
text = "";
String[] tableType = {"TABLE"}; //nur Benutzertabellen
ResultSet rsTab = dbmd.getTables(null,null,"%",tableType);
//
ResultSet rsTab = dbmd.getTables(null,null,"%",null); //ALLE Tabellen
ResultSet rsCol;
String table, l20 = "
";
while (rsTab.next()){
table = rsTab.getString("TABLE_NAME");
text = rsTab.getString("TABLE_TYPE")+":\t"+table + "\n";
area.append("\n"+text);
text = "";
rsCol = dbmd.getColumns(null,null,table,"%");
while (rsCol.next()){
text += "\t"+(rsCol.getString("COLUMN_NAME")+l20).substring(0,19);
text += "\t"+(rsCol.getString("TYPE_NAME") +l20).substring(0,10) ;
text += "\t"+(rsCol.getString("DATA_TYPE") +l20).substring(0,4) ;
text += "\t"+ rsCol.getString("REMARKS")
+"\n";
}
area.append(text);
}
}
catch (Exception e){
area.setText(e.toString());
}
}
public static void main(String args[]){
System.out.println("Starting JavaDBTabellen...");
JavaDBTabellen mainFrame = new JavaDBTabellen();
mainFrame.setSize(550, 400);
mainFrame.setTitle("JavaDBTabellen");
mainFrame.setVisible(true);
}
}
Tabelle
Datenwerte einer Tabelle ausgeben
Die in der Tabelle enthalten Inhalte der Felder, also die „Tabelle“ selbst, sind nach Absetzen der SQLAnweisung SELECT * FROM <Tabelle> mittels eines ResultSet verfügbar. Dazu muss der Name der Tabelle bekannt sein, zum Beispiel mittels des Verfahrens aus dem vorigen Kapitel.
Senden eines SQL-Strings an eine Tabelle
Erst muss ein Objekt der Klasse Statement erzeugt werden.
Darin ist die Methode execute() enthalten, die als Parameter
den SQL-String an die Datenbank-Tabelle übergibt. Mittels
dieser execute-Methode kann man also in Form von SQLAnweisungen Informationen über die zu liefernden Daten an
die Datenbank schicken. Die Rückgaben der Datenbank sind
in einem ResultSet verfügbar
Statement
execute
getResultSet: ResultSet
SQLException
14
Tabelle
Tabellenwerte lesen
Statement tbstat = con.createStatement();
boolean control = tbstat.execute("SELECT * FROM Artikel");
Tabellenwerte lesen
Die Daten der Tabelle sind mittels ResultSet dem Statement-Objekt zu entnehmen:
ResultSet tbrs = tbstat.getResultSet();
Aus diesem ResultSet kann man zunächst die MetaDaten der Tabelle, also die Feldnamen („Köpfe“ der Spalten), auslesen. Dazu erzeugt man erst ein Objekt aus der Klasse ResultSetMetaData:
ResultSetMetaData tbmd = tbrs.getMetaData();
int columns = tbmd.getColumnCount();
for (int i = 1; i <= columns; i++){
text += tbmd.getColumnName(i) + " | ";
}
Und weiter erhält man durch wiederholte Aufrufe der
getString-Methode des ResultSet in einer Schleife die Tabellendaten (Feldwerte) Zeile für Zeile. Beachten Sie, dass
Sie dieser Methode entweder die Nummer oder den Bezeichner (Kopf) der Spalte übergeben können!
text = "";
while (tbrs.next()){
for (int i = 1; i <= columns; i++){
text += tbrs.getString(i) + " ";
}
text += "\n";
}
area.append(text);
ResultSet
getMetaData: ResultSetMetaData
next
getString
ResultSetMetaData
getColumnName
getColumnCount
SQLException
Bei diesem Verfahren können zwei Fehler auftreten:
1. Die Datenbank „versteht“ das übergebene SQL-Statement nicht und kann es nicht ausführen. Deshalb gibt tbstat.execute(SQL-String) einen bool-Wert zurück. Nur bei 'true' darf aus dem Statement
ein ResultSet erzeugt werden.
2. Sie kann nichts zurückgeben, weil die Ergebnismenge leer ist: die Suchanfrage kann keinerlei Treffer ergeben, weil kein Datensatz dieser Bedingung entspricht. Die Rückgabemenge ist daher die leere Menge. Dieser Fall muss vom aufrufenden Programm berücksichtigt werden. Im folgenden Beispiel wird einfach die Verbindung geschlossen.
Im folgenden Programmausschnitt wird die SQL-Anweisung aus einem Textfeld eingelesen und die Rückgabe der Datenbank an die Methode display() übergeben. Die Rückgabe einer leeren Menge schließt die
Datenbankabfrage.
boolean control = tbstat.execute(sql.getText());
if (control)
{
ResultSet tbmd = tbstat.getResultSet();
if (tbmd != null)
{
display(tbmd);
}
else{
area.setText("");
con.close();
}
}
Mit einigen kosmetischen Korrekturen und einem Textfeld zur Eingabe des SQL-Strings während der Laufzeit kann man dieses Ergebnis erzielen:
15
Tabelle
Tabellenwerte lesen
Und nun auch hierzu der komplette Quellcode:
import java.awt.*;
import java.awt.event.*;
import java.sql.*;
class JavaSQL extends Frame implements ActionListener{
Label lbdb = new Label("URL = jdbc:odbc:");
TextField url= new TextField("MS Datenbank",40);
Label lbsql = new Label("SQL =");
TextField sql= new TextField("SELECT * FROM ",40);
Button execute = new Button("
Ausführen
");
TextArea area = new TextArea(20, 100);
Font courier = new Font("Courier",Font.PLAIN,12);
public JavaSQL(){
addWindowListener(new WindowAdapter(){
public void windowClosing(WindowEvent e){
dispose();
System.exit(0);
}
});
setLayout(new FlowLayout());
add(lbdb);
add(url);
add(lbsql);
add(sql);
add(execute);
execute.addActionListener(this);
add(area);
area.setFont(courier);
}
public void actionPerformed(ActionEvent e){
if (e.getSource() == execute)
{
accessDatabase();
}
}
public void accessDatabase(){
try
{
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
Connection con = DriverManager.getConnection("jdbc:odbc:"+url.getText());
//Name in ODBC-Manager festlegen
// muss _nicht_ gleich DB-Name sein!!
Statement tbstat = con.createStatement();
boolean control = tbstat.execute(sql.getText());
if (control)
{
ResultSet tbrs = tbstat.getResultSet();
if (tbrs != null)
{
display(tbrs);
16
Tabelle
Tabellenwerte lesen
}
else{
area.setText("");
con.close();
}
}
}
catch (Exception e){
area.setText(e.toString());
}
}
public void display(ResultSet tbrs){
try
{
ResultSetMetaData tbmd = tbrs.getMetaData();
int columns = tbmd.getColumnCount();
String text = "| ";
for (int i = 1; i <= columns; i++){
text += tbmd.getColumnName(i) + "\t | ";
}
text += "\n";
area.setText(text);
text = "";
while (tbrs.next()){
text += "| ";
for (int i = 1; i <= columns; i++){
text += tbrs.getString(i) + "\t | ";
// Feldname ODER Spaltennummer 1..n
}
text += "\n";
}
area.append(text);
}
catch (SQLException e){
area.setText(e.toString());
}
}
public static void main(String args[]){
System.out.println("Starting JavaSQL...");
JavaSQL mainFrame = new JavaSQL();
mainFrame.setSize(800, 450);
mainFrame.setTitle("JavaSQL");
mainFrame.setVisible(true);
}
}
17
Datenzugriff auf ODBC-Datenbanken unter Java
Tabellenwerte lesen
Datenzugriff auf ODBC-Datenbanken unter Java
Datenbank
(z.B. ACCESS)
DriverManager
getConnection
Connection
createStatement
getMetaData
close
Exception
Statement
execute
getResultSet: ResultSet
DatabaseMetaData
SQLException
ResultSet
getDatabaseProduktName(): String
getDatabaseProduktVersion(): String
...
getTables(): ResultSet
getColumns(): ResultSet
getMetaData: ResultSetMetaData
next
getString
ResultSetMetaData
ResultSet
next
getString("TABLE_NAME")
getString("COLUMN_NAME")
Aussagen
über
Datenbank
getColumnName
getColumnCount
SQLException
Exception
Aussagen
über
Daten in den Tabellen
18
Typkonvertierung
Tabellenwerte lesen
Typkonvertierung
Die Datenübernahme ist nicht ganz problemlos: es ist darauf zu achten, dass die gespeicherten Datentypen
verträglich sind mit den Typen auf die die Ausgabe erfolgt. Bei ungeschickter Wahl sind Datenverluste möglich!
Dabei unterscheiden wir zwei Richtungen der Typkonvertierung: Die erste ist die Typkonvertierung von
SQL nach Java, wobei jedoch nicht notwendigerweise alle SQL-Typen in allen Datenbanken unterstützt
werden. Die zweite geht in die entgegengesetzte Richtung
Java Æ SQL
SQL type
VARCHAR oder
String
LONGVARCHAR
java.sql.Numeric
NUMERIC
boolean
BIT
byte
TINYINT
short
SMALLINT
int
INTEGER
long
BIGINT
float
REAL
double
DOUBLE
VARBINARY oder
byte[]
LONGVARBINARY
java.sql.Date
DATE
java.sql.Time
TIME
java.sql.Timestamp
TIMESTAMP
Java type
SQL Æ Java
SQL type
Java type
CHAR
String
VARCHAR
String
LONGVARCHAR
String
NUMERIC
java.sql.Numeric
DECIMAL
java.sql.Numeric
BIT
boolean
TINYINT
byte
SMALLINT
short
INTER
int
BIGINT
long
REAL
float
FLOAT
double
DOUBLE
double
BINARY
byte[]
VARBINARY
byte[]
LONGVARBINARY
byte[]
DATE
java.sql.Date
TIME
java.sql.Time
TIMESTAMP
java.sql.Timestamp
19
Herunterladen