Java -Zugriff auf Microsoft ® Access
Es wird eine kleine Datenbank mit einer Tabelle "simple" mit drei Spalten und zwei Zeilen angelegt, die zu einer Person einen Namen und einen Saldo enthält und eine ODBC -Datenquelle "Simple" für diese Datenbank angelegt. (Die dafür notwendigen Kenntnisse über Microsoft ® Access und Microsoft ® Windows werden in dieser Lektion nicht gelehrt.)
jdbc:odbc:Simple/simple.tab
"id", "name", "saldo",
"1", "Mueller", "12",
"2", "Meyer", "14",
Für das folgende Programm ist es nur wichtig, daß die Datenquelle "Simple" und darin die Tabelle "simple" vorhanden ist. Der Inhalt der Tabelle könnte auch ein anderer sein.
Das Programm ist zunächst als Abfolge folgender Schritte organisiert:
main
Start.appendToOutput( log, output )
Anhängen des Ergebnisses an »output«
(Nach einer Überarbeitung des Programms ist die folgende Beschreibung nicht mehr passend. Sie muß noch entsprechend überarbeitet werden.)
appendToOutput( log, output, conn )
Anhängen des Ergebnisses an »output« bei vorhandener Verbindung »conn«appendToOutput( log, output, statement )
Anhängen des Ergebnisses an »output« bei vorhandener Anweisung »statement«appendToOutput( log, output, results )
Anhängen des Ergebnisses an »output« bei vorhandenen Ergebnissen »result«appendTitle( log, output, desc )
Anhängen des Tabellenkopfs des Ergebnisses an »output«appendBody( log, output, results )
Anhängen des Tabellenrumpfs Ergebnisses an »output« bei vorhandenen Ergebnissen »results«
Bei Ausnahme oder Störungen wird die Abfolge abgebrochen, wobei durch das Programm dafür Sorge getragen wird, daß in jedem Fall genau die erfolgreich erlangten Ressourcen wieder freigegeben werden.
Ressource-Bedingung Genau die Ressourcen müssen bei Beendigung eines Vorganges (wenn sie nicht mehr benötigt werden) wieder freigegeben werden, die zuvor erfolgreich erlangt wurden.
Nur in der Methode "main" ist das Programm mit einem bestimmten Ausgabegerät (hier das Objekt "java.lang.System.out") fest verbunden. Dadurch, daß die anderen Methoden davon entkoppelt sind, können sie leicht in einer anderen Umgebung verwendet werden, in der das Objekt "java.lang.System.out" nicht für Mitteilungen an den Benutzer verwendet werden kann oder soll.
Main.java
public class Main
{
final static String driver = "sun.jdbc.odbc.JdbcOdbcDriver";
final static String source = "jdbc:odbc:Simple";
final static String table = "simple";
final static String query = "SELECT * FROM " + table;
final static String eol =
java.lang.System.getProperty( "line.separator" );
/** Startpunkt des Programms. */
public static void main( final java.lang.String[] args )
{ /*logging is needed to avoid a close exception
from shadowing a previous exception. */
final java.util.ArrayList<java.lang.Throwable> log
= new java.util.ArrayList<java.lang.Throwable>( 16 );
final java.lang.StringBuilder output
= new java.lang.StringBuilder();
try
{ java.lang.Class.forName( driver ); // load driver
appendToOutput( log, output ); }
catch( final java.sql.SQLException sQLException )
{ log.add( sQLException ); }
catch( final ClassNotFoundException classNotFoundException )
{ log.add( classNotFoundException ); }
if( output.length() > 0 )
java.lang.System.out.println( output );
if( log.size() > 0 )
java.lang.System.err.println( log ); }
private static void appendToOutput
( final java.util.ArrayList<java.lang.Throwable> log,
final java.lang.StringBuilder output )
throws java.sql.SQLException
{ final java.sql.Connection conn =
java.sql.DriverManager.getConnection( source );
try
{ appendToOutput( log, output, conn ); }
finally // must never throw, to not shadow another exception
{ try
{ conn.close(); }
catch( final java.lang.Exception exception )
{ log.add( exception ); }}}
private static void appendToOutput
( final java.util.ArrayList<java.lang.Throwable> log,
final java.lang.StringBuilder output,
final java.sql.Connection conn )
throws java.sql.SQLException
{ final java.sql.Statement statement = conn.createStatement();
try
{ if( statement.execute( query ))
appendToOutput( log, output, statement ); }
finally
{ try
{ statement.close(); }
catch( final java.lang.Exception exception )
{ log.add( exception ); }}}
private static void appendToOutput
( final java.util.ArrayList<java.lang.Throwable> log,
final java.lang.StringBuilder output,
final java.sql.Statement statement )
throws java.sql.SQLException
{ final java.sql.ResultSet results = statement.getResultSet();
if( results != null )
{ try
{ appendToOutput( log, output, results ); }
finally
{ try
{ set.close(); }
catch( final java.lang.Exception exception )
{ log.add( exception ); }}}}
private static void appendToOutput
( final java.util.ArrayList<java.lang.Throwable> log,
final java.lang.StringBuilder output,
final java.sql.ResultSet results )
throws java.sql.SQLException
{ final java.sql.ResultSetMetaData desc = results.getMetaData();
appendTitle( log, output, desc );
appendBody( log, output, desc, results ); }
private static void appendTitle
( final java.util.ArrayList<java.lang.Throwable> log,
final java.lang.StringBuilder output,
final java.sql.ResultSetMetaData desc )
throws java.sql.SQLException
{ final int cols = desc.getColumnCount();
for( int i = 1; i <= cols; ++i )
output.append( desc.getColumnName( i )+ " " );
output.append( eol ); }
private static void appendBody
( final java.util.ArrayList<java.lang.Throwable> log,
final java.lang.StringBuilder output,
final java.sql.ResultSetMetaData desc,
final java.sql.ResultSet results )
throws java.sql.SQLException
{ final int cols = desc.getColumnCount();
String text = "";
while( results.next() )
{ for( int i = 1; i <= cols; ++i )
output.append( set.getString( i )+ " " );
output.append( eol ); }}}java.lang.System.out
id name saldo
1 Mueller 12
2 Meyer 14
Durch die Unterteilung in einzelne Methoden ist das Geschehen übersichtlich: Jede einzelne Methode erledigt eine ganz bestimmte, überschaubare Aufgabe, und es kann anhand ihres Quelltextes leicht nachvollzogen werden, daß sie ihre Aufgaben so erfüllt, daß die oben genannte Ressourcen-Bedingung erfüllt ist. Durch die Wahl der Parameter können weiter hinten stehende Methoden auch in einer Schleife oder von Klienten aufgerufen werden, welche die nötigen Ressourcen selber schon haben: Ein Klient, der schon eine Datenbankverbindung hat, kann beispielsweise direkt die Methode für Verwendung bei vorhandener Datenbankverbindung aufrufen und die Methoden zur Erstellung der Verbindung ignorieren. Er kann diese Methode "thenCreateStatement" auch in einer Schleife aufrufen und dabei die bestehende Verbindung weiterverwenden.
Wenn das Programm so verändert wird, daß der Treiber, die Quelle, die Tabelle oder das Kommando nicht gefunden wird, indem diesen das Zeichen "0" vorangestellt wird, ergeben sich unter der vom Autor verwendeten Testumgebung jeweils charakteristische Fehlermeldungen. Diese Fehlermeldungen geben daher auch Hinweise, wo das Problem liegen könnte, wenn eine der Fehlermeldungen erscheint.
final static String driver = "0sun.jdbc.odbc.JdbcOdbcDriver";
java.lang.ClassNotFoundException: 0sun/jdbc/odbc/JdbcOdbcDriver
final static String source = "0jdbc:odbc:Simple";
java.sql.SQLException: No suitable driver
final static String table = "0simple";
java.sql.SQLException: [Microsoft][ODBC Microsoft Access Driver] Das Microsoft Jet-Datenbankmodul findet die Eingangstabelle oder Abfrage '0simple' nicht. Stellen Sie sicher, dass sie existiert und der Name richtig eingegeben wurde.
final static String query = "0SELECT * FROM " + table;
java.sql.SQLException: [Microsoft][ODBC Microsoft Access Driver] Unzulässige SQL-Anweisung; 'DELETE', 'INSERT', 'SELECT' oder 'UPDATE' erwartet.