Udo Matthias Munz Datenbanken und SQL mit Einführung Informationstechnik Zugriff auf eine Datenbank................................................................................................................ 2 ODBC...................................................................................................................................... 2 Eine DSN einrichten................................................................................................................ 3 Verbindung zu einer Datenbank ........................................................................................................ 4 Datenbank .......................................................................................................................................... 4 Metadaten der Datenbank holen.............................................................................................. 4 Namen der Tabellen und deren Eigenschaften holen .............................................................. 6 Tabelle ............................................................................................................................................... 9 Metadaten einer Tabelle ausgeben .......................................................................................... 9 Senden eines SQL-Strings an eine Tabelle.............................................................................. 9 Tabellenwerte lesen ................................................................................................................. 9 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. 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. 2 Zugriff auf eine 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 ACCESS-Datenbank aus: 3 Verbindung zu einer Datenbank Metadaten der Datenbank holen In diesem Beispiel ist die unter ACCESS erstellte Datenbank ITC-2000.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 zu einer Datenbank Es muss das Paket java.sql in den Programmcode importiert werden. 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: 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 con = DriverManager.getConnection ("jdbc:odbc:ITC"); 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. Zunächst wollen wir die Metadaten der Datenbank erfragen. Das zu 4 Datenbank Metadaten der Datenbank holen erstellen wir ein Objekt der Klasse DatabaseMetaData. mit der Methode getMetaData() des eben erstellten Objekts con: DatabaseMetaData dbmd = con.getMetaData(); Metadaten kann man nun direkt mit den entsprechenden Methoden auslesen und beispielsweise in einem TextArea ausgeben: text = ""; text += "Datenbank: text += "Version: area.setText(text); " + dbmd.getDatabaseProductName() + "\n"; " + dbmd.getDatabaseProductVersion() + "\n"; 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 dieses Fenster 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(); 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){ 5 Datenbank Namen der Tabellen und deren Eigenschaften holen 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 result){ String text = "Metadaten der Datenbank"+"\n\n"; area.setText(text); try{ text = ""; text += "Katalog: " + result.getCatalogTerm() + "\n"; text += "Datenbank: " + result.getDatabaseProductName() + "\n"; text += "Version: " + result.getDatabaseProductVersion() + "\n"; text += "Treibername: " + result.getDriverName() + "\n"; text += "Version: " + result.getDriverVersion() + "\n"; text += "URL: " + result.getURL() + "\n"; text += "User: " + result.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); } } Namen der Tabellen und deren Eigenschaften holen Das vorige Beispiel gibt nicht so sehr interessante Daten preis. Um die beispielsweise die Namen der in der Datenbank enthaltenen Tabellen zu erfahren muss man mit einem weiteren Zwischenschritt diese aus den Metadaten extrahieren. Es ist deshalb so kompliziert, weil man nicht von vornherein sagen kann, wie viele Tabellen vorkommen, und welche Felder diese enthalten. Das Auslesen geschieht mit Hilfe einer weiteren Klasse: ResultSet. Nach dem Erzeugen eines Objektes dieser Klasse mit der Methode getTables() aus dem DatabaseMetaData-Objekt 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 = result.getTables(null,null,"%",tableType); Der wiederholte Aufruf der Methode rsTab.getString("TABLE_NAME") gibt je Aufruf einen weiteren Tabellennamen aus. table = rsTab.getString("TABLE_NAME"); Die Namen der Felder die in dieser Tabelle enthalten sind erhält man nach dem Erzeugen eines weiteren ResultSet: 6 Datenbank Namen der Tabellen und deren Eigenschaften holen rsCol = result.getColumns(null,null,table,"%"); Aus diesem ResultSet erhalten Sie nacheinander die einzelnen Feldnamen durch wiederholten Aufruf der Methode rsCol.getString("COLUMN_NAME") 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 = ""; rsCol = result.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); 7 Datenbank Button execute = new Button(" Ausführen TextArea area = new TextArea(20, 70); Namen der Tabellen und deren Eigenschaften holen "); 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()); DatabaseMetaData dbmd = con.getMetaData(); display(dbmd); } catch (Exception e){ area.setText(e.toString()); } } public void display(DatabaseMetaData result){ String text = ""; try{ text = "Tabellen der Datenbank: " + result.getURL() + "\n"; area.setText(text); text = ""; String[] tableType = {"TABLE"}; //nur Benutzertabellen ResultSet rsTab = result.getTables(null,null,"%",tableType); // ResultSet rsTab = result.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 = result.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..."); 8 Tabelle Metadaten einer Tabelle ausgeben JavaDBTabellen mainFrame = new JavaDBTabellen(); mainFrame.setSize(550, 400); mainFrame.setTitle("JavaDBTabellen"); mainFrame.setVisible(true); } } Tabelle Metadaten einer Tabelle ausgeben Die Metadaten der Tabelle enthalten die Inhalte der Felder, also die „Tabelle“ selbst. Nach Absetzen der SQL-Anweisung SELECT * FROM <Tabelle> sind die entsprechenden Werte als Metadaten vorhanden. 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 Tabelle übergibt. Statement statement = con.createStatement(); boolean control = statement.execute("SELECT * FROM Artikel"); Tabellenwerte lesen Die Daten sind mittels ResultSet der Tabelle zu entnehmen: ResultSet result = statement.getResultSet(); Aus diesem ResultSet kann zunächst die MetaDaten der Tabelle, also die Feldnamen, auslesen: ResultSetMetaData meta = result.getMetaData(); int columns = meta.getColumnCount(); for (int i = 1; i <= columns; i++){ text += meta.getColumnName(i) + " | "; } Und weiter erhält man durch wiederholte Aufrufe in einer Schleife die Tabellendaten Zeile für Zeile die Feldwerte durch Aufrufe der Methode getString(). Beachten Sie, dass Sie dieser Methode entweder die Nummer oder den Bezeichner der Spalte übergeben können! text = ""; while (result.next()){ for (int i = 1; i <= columns; i++){ text += result.getString(i) + " | "; } text += "\n"; } area.append(text); Mit einigen kosmetischen Korrekturen und einem Textfeld zur Eingabe des SQL-Strings während der Laufzeit kann man dieses Ergebnis erzielen: 9 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 statement = con.createStatement(); 10 Tabelle Tabellenwerte lesen boolean control = statement.execute(sql.getText()); if (control) { ResultSet result = statement.getResultSet(); if (result != null) { display(result); } else{ area.setText(""); con.close(); } } } catch (Exception e){ area.setText(e.toString()); } } public void display(ResultSet result){ try { ResultSetMetaData meta = result.getMetaData(); int columns = meta.getColumnCount(); String text = "| "; for (int i = 1; i <= columns; i++){ text += meta.getColumnName(i) + "\t | "; } text += "\n"; area.setText(text); text = ""; while (result.next()){ text += "| "; for (int i = 1; i <= columns; i++){ text += result.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); } } 11