FHZ Hochschule Technik+Architektur Luzern Abteilung Informatik, Swing/JFC K10 Datenanbindung K10 Datenanbindung • Inhalt 1. Files 1. Text-Files 2. StreamTokanizer 3. Objekt-Serialisierung 2. Datenbanken 1. 2. 3. 4. JDBC Driver JDBC Connection JDBC Statement ResultSets 3. JTable 1. ResultSet TableModel 2. Editieren Abteilung Informatik, JFC/Swing 2004 © Diego Schmidlin V2.2 K10 Datenanbindung Folie 1 Lernziele • Sie können Textfiles Einlesen und in Token zerlegen • Sie wissen, was Persistenz ist und wie der Zustand von Objekten gesichert/gelesen werden kann • Sie kennen die Arbeitsweise/Architektur von JDBC • Sie können über JDBC – – – – eine Verbindung zu einer Datenbank herstellen eine Abfrage absetzen die Resultate auswerten Daten verändern • Sie wissen, wie Datenbanken in TableModel verwendet werden Abteilung Informatik, JFC/Swing 2004 © Diego Schmidlin V2.2 K10_Datenanbindung-P.ppt, V2.2 2004 © Diego Schmidlin K10 Datenanbindung Folie 2 Seite 1 FHZ Hochschule Technik+Architektur Luzern Abteilung Informatik, Swing/JFC K10 Datenanbindung 1.1 Text in "data1.txt" schreiben: Beispiel (1) import java.io.*; import java.text.*; public class WriteTextFile1 { public static void main(String[] args) { String fileName = "data1.txt"; File aFile = new File(fileName); if (!aFile.exists()) { try { FileWriter aFileWriter = new FileWriter(aFile); BufferedWriter aBufferedWriter = new BufferedWriter(aFileWriter); PrintWriter aPrintWriter = new PrintWriter(aBufferedWriter); aPrintWriter.println("This is the 1. line."); aPrintWriter.println("This is the 2. line."); Abteilung Informatik, JFC/Swing 2004 © Diego Schmidlin V2.2 K10 Datenanbindung Folie 3 1.1 Text in "data1.txt" schreiben: Beispiel (2) DecimalFormat df = new DecimalFormat("' '0000.000;-0000.000"); aPrintWriter.print(df.format(12.3)); aPrintWriter.print(" "); aPrintWriter.print(df.format(10)); aPrintWriter.println(); aPrintWriter.print(df.format(1111.22222)); aPrintWriter.print(" "); aPrintWriter.print(df.format(-10.1)); aPrintWriter.flush(); aFileWriter.close(); } catch (IOException e) { System.out.println("Exception: " + e.getMessage()); return; } } } } Abteilung Informatik, JFC/Swing 2004 © Diego Schmidlin V2.2 K10_Datenanbindung-P.ppt, V2.2 2004 © Diego Schmidlin K10 Datenanbindung Folie 4 Seite 2 FHZ Hochschule Technik+Architektur Luzern Abteilung Informatik, Swing/JFC K10 Datenanbindung 1.1 Text von "data1.txt" lesen: Beispiel (1) public class ReadTextFile1 { public static void main(String[] args) { String fileName = "data1.txt"; File aFile = new File(fileName); if (aFile.exists()) { try { FileReader aFileReader = new FileReader(aFile); BufferedReader aBufferedReader = new BufferedReader(aFileReader); System.out.println(aBufferedReader.readLine()); System.out.println(aBufferedReader.readLine()); Abteilung Informatik, JFC/Swing 2004 © Diego Schmidlin V2.2 K10 Datenanbindung Folie 5 1.1 Text von "data1.txt" lesen: Beispiel (2) String line; StringTokenizer sT; double d; while ((line = aBufferedReader.readLine()) != null) { sT = new StringTokenizer(line); while (sT.hasMoreTokens()) { d = (Double.valueOf( sT.nextToken())).doubleValue(); // Put your code here System.out.println(d); } } aFileReader.close(); } catch (IOException e) { System.out.println("Exception: " + e.getMessage()); return; } } } } Abteilung Informatik, JFC/Swing 2004 © Diego Schmidlin V2.2 K10_Datenanbindung-P.ppt, V2.2 2004 © Diego Schmidlin K10 Datenanbindung Folie 6 Seite 3 FHZ Hochschule Technik+Architektur Luzern Abteilung Informatik, Swing/JFC K10 Datenanbindung 1.2 Klasse StreamTokenizer (1) • Klasse StreamTokenizer – Auch in Package java.io definiert – Nützliche Methoden zur lexikalischen Analyse • Groben Syntaxanalyse eines Datenstroms StreamTokenizer nval:double sval:String ttype:int commentChar(int ch):void nextToken():int ordinaryChar(int ch):void resetSyntax():void Abteilung Informatik, JFC/Swing 2004 © Diego Schmidlin V2.2 K10 Datenanbindung Folie 7 1.2 Klasse StreamTokenizer (2) StreamTokenizer wird an Datenstrom angehängt • Methoden – Beschränkte Definition einer Syntax • • • • Whitespace Normale Zeichen Sonderzeichen Kommentare • Aufruf nextToken() entnimmt dem Datenstrom das nächste Token – Zeichenketten und Zahlenwerte werden automatisch in Strings bzw. double-Werte umgewandelt. Abteilung Informatik, JFC/Swing 2004 © Diego Schmidlin V2.2 K10_Datenanbindung-P.ppt, V2.2 2004 © Diego Schmidlin K10 Datenanbindung Folie 8 Seite 4 FHZ Hochschule Technik+Architektur Luzern Abteilung Informatik, Swing/JFC K10 Datenanbindung 1.2 Klasse StreamTokenizer (3) • Beispiel – Von einem Textfile sollen, abgesehen von Kommentaren, Zeichenketten und Zahlenwerte eingelesen werden: Abteilung Informatik, JFC/Swing 2004 © Diego Schmidlin V2.2 K10 Datenanbindung Folie 9 1.2 Klasse StreamTokenizer: Beispiel (1) import java.io.*; import java.util.StringTokenizer; public class TokenizerDemo { public static void main(String[] args) throws IOException { if (args.length == 1) { Reader aReader = new FileReader(args[0]); StreamTokenizer sT = new StreamTokenizer(aReader); sT.ordinaryChar('/'); // recognizes C++-style comments sT.slashSlashComments(true); // recognizes C-style comments sT.slashStarComments(true); // numbers should be parsed sT.parseNumbers(); // treats end of lines as tokens sT.eolIsSignificant(true); Abteilung Informatik, JFC/Swing 2004 © Diego Schmidlin V2.2 K10_Datenanbindung-P.ppt, V2.2 2004 © Diego Schmidlin K10 Datenanbindung Folie 10 Seite 5 FHZ Hochschule Technik+Architektur Luzern Abteilung Informatik, Swing/JFC K10 Datenanbindung 1.2 Klasse StreamTokenizer: Beispiel (2) int tval; while ((tval = sT.nextToken()) != StreamTokenizer.TT_EOF) { switch (tval) { case StreamTokenizer.TT_NUMBER : System.out.print("[N: " + sT.nval + " ]"); break; case StreamTokenizer.TT_WORD : System.out.print("[S: " + sT.sval + " ]"); break; case StreamTokenizer.TT_EOL : System.out.println(); break; default : System.out.print("[X: " + sT.ttype + " ]"); } } aReader.close(); } else { System.exit(1); } }} Abteilung Informatik, JFC/Swing 2004 © Diego Schmidlin V2.2 K10 Datenanbindung Folie 11 1.3 Objekt-Serialisierung (1) • Bisherige I/O-Möglichkeiten – Elementare Datentypen: byte, char, int, String • Wunsch, Anforderung der OOP – Ein-/ Ausgabe von Objekten Objekte ObjektSerialisierung Werte der Instanzvariablen Byte-Datenstrom Abteilung Informatik, JFC/Swing 2004 © Diego Schmidlin V2.2 K10_Datenanbindung-P.ppt, V2.2 2004 © Diego Schmidlin K10 Datenanbindung Folie 12 Seite 6 FHZ Hochschule Technik+Architektur Luzern Abteilung Informatik, Swing/JFC K10 Datenanbindung 1.3 Objekt-Serialisierung (2) • Objekt-Serialisierung – Speichern und wieder Einlesen von Objekten • Auf anderem Rechner oder via Internet • Objekte, die ausserhalb eines Laufzeitsystems existieren werden persistente Objekte genannt – Instanzvariablen werden in Byte-Datenstrom geschrieben • Marshalling/Unmarshalling – Klassenvariablen werden nicht serialisiert! ObjectOutputStream, ObjectInputStream • Ausgabestrom kann mit FileOutputStream verbunden werden Abteilung Informatik, JFC/Swing 2004 © Diego Schmidlin V2.2 K10 Datenanbindung Folie 13 1.3 Objekt-Serialisierung (3) • Modifier transient – Instanzvariablen werden nicht serialisiert • Hilfsvariablen • Sicherheitsgründe transient int currentVolume; • Interface Serializable – Klassen, die serialisiert werden sollen müssen das Interface Serializable implementieren – Leeres Interface • Marker-Interface • Erlaubt durch Überprüfung des Klassen-Typs die Serialisierung Abteilung Informatik, JFC/Swing 2004 © Diego Schmidlin V2.2 K10_Datenanbindung-P.ppt, V2.2 2004 © Diego Schmidlin K10 Datenanbindung Folie 14 Seite 7 FHZ Hochschule Technik+Architektur Luzern Abteilung Informatik, Swing/JFC K10 Datenanbindung 1.3 Objekt-Serialisierung: Beispiel (1) import java.io.*; public class SerializationDemo { public static void main(String[] args) throws Exception { // Integer implements interface Serializable Integer i = new Integer(2000); System.out.println("i = " + i); // Write Object FileOutputStream aFileOutputStream = new FileOutputStream("temp.dat"); ObjectOutputStream aObjectOutputStream = new ObjectOutputStream(aFileOutputStream); aObjectOutputStream.writeObject(i); aFileOutputStream.close(); Abteilung Informatik, JFC/Swing 2004 © Diego Schmidlin V2.2 K10 Datenanbindung Folie 15 1.3 Objekt-Serialisierung: Beispiel (2) // Read Object FileInputStream aFileInputStream = new FileInputStream("temp.dat"); ObjectInputStream aObjectInputStream = new ObjectInputStream(aFileInputStream); Object o = aObjectInputStream.readObject(); aFileInputStream.close(); Integer j = (Integer)o; System.out.println("j = " + j); } } Abteilung Informatik, JFC/Swing 2004 © Diego Schmidlin V2.2 K10_Datenanbindung-P.ppt, V2.2 2004 © Diego Schmidlin K10 Datenanbindung Folie 16 Seite 8 FHZ Hochschule Technik+Architektur Luzern Abteilung Informatik, Swing/JFC K10 Datenanbindung 2.1 JDBC Driver (1) • Vor dem Öffnen einer Verbindung muss der JDBC-Driver geladen werden – Über statische Methode Class.forName("Drivername"); – Über Konstruktor Class.forName("Drivername").newInstance(); – Über statische Methode DriverManager.registerDriver( new Drivername() ); – Typische Driver-Namen sun.jdbc.odbc.JdbcOdbcdriver oracle.jdbc.driver.OracleDriver Abteilung Informatik, JFC/Swing 2004 © Diego Schmidlin V2.2 K10 Datenanbindung Folie 17 2.2 JDBC Connection (1) • Die Klasse Connection dient zur Verbindung mit einer Datenbank • Erzeugt wird diese Verbindung vom JDBC DriverManager Connection con = DriverManager.getConnection(String url); • Varianten von getConnection static Connection getConnection(String url) static Connection getConnection(String url, String user, String password) Abteilung Informatik, JFC/Swing 2004 © Diego Schmidlin V2.2 K10_Datenanbindung-P.ppt, V2.2 2004 © Diego Schmidlin K10 Datenanbindung Folie 18 Seite 9 FHZ Hochschule Technik+Architektur Luzern Abteilung Informatik, Swing/JFC K10 Datenanbindung 2.2 JDBC Connection (2) • Der URL hat eine der folgenden Formen: – Lokale Datenbank mit JDBC-Driver jdbc:protocol:databasename – Datenbank auf anderem Rechner mit JDBC-Driver jdbc:protocol://hostname:port/databasename – Lokale ODBC Datenbank mit JDBC-ODBC-Driver jdbc:odbc:datasourcename – ODBC Datenbank auf anderem Rechner mit JDBC-ODBC-Driver jdbc:odbc://hostname/datasourcename Abteilung Informatik, JFC/Swing 2004 © Diego Schmidlin V2.2 K10 Datenanbindung Folie 19 2.2 JDBC Connection (3) • Wichtigste Methoden Methode Beschreibung Statement createStatement() Erzeugt ein Statement für die Ausführung von SQL-Befehlen PreparedStatement prepareStatement(String sql) Erzeugt ein Prepared Statement für die optimierte Ausführung von SQL-Befehlen DatabaseMetaData getMetaData() Liefert Metadaten (DDL) der Datenbank void setReadOnly(boolean readOnly) true: Es werden nur Datenbankabfragen durchgeführt false: Abfragen und Updates sind möglich void setAutoCommit(boolean autoCommit) true: Jedes SQL-Statement wird als eigene Transaktion ausgeführt false: Mehrere SQL-Statements müssen mit commit() und rollback() zu einer Transaktion zusammengefasst werden void commit() Beendet eine Transaktion erfolgreich void rollback() Beendet eine Transaktion im Fehlerfall. Alle Änderungen seit Beginn der Transaktion werden rückgängig gemacht void close() Beendet die Verbindung mit der Datenbank Abteilung Informatik, JFC/Swing 2004 © Diego Schmidlin V2.2 K10_Datenanbindung-P.ppt, V2.2 2004 © Diego Schmidlin K10 Datenanbindung Folie 20 Seite 10 FHZ Hochschule Technik+Architektur Luzern Abteilung Informatik, Swing/JFC K10 Datenanbindung 2.3 JDBC Statement (1) • Das Interface Statement definiert Methoden zur Ausführung eines oder mehrerer SQL-Statements • Erzeugt wird diese Statement von der Connection Statement stmt = con.createStatement(); • Wichtigste Methoden Methode Beschreibung ResultSet executeQuery(String sql) Führt SQL-Statement aus und gibt Resultat als ResultSet zurück int executeUpdate(String sql) Führt SQL-Statement aus, das kein Resultat liefert. Rückgabewert ist Anzahl Records, die vom Befehl betroffen waren boolean execute(String sql) Führt SQL-Statement aus, das mehrere ResultSets liefern kann void setQueryTimeout(int seconds) Setzt Zeitlimit für die Durchführung von Abfragen void close() Beendet Statement Abteilung Informatik, JFC/Swing 2004 © Diego Schmidlin V2.2 K10 Datenanbindung Folie 21 2.3 JDBC Statement (2) • Beispielskizze für Abfrage Statement stmt = con.createStatement(); ResultSet rs = stmt.executeQuery ("SELECT LastName, Salary, Age FROM Employees"); ... stmt.close(); • Beispielskizze für Update Statement stmt = con.createStatement(); int rowCount = stmt.executeUpdate("UPDATE Employees" + "SET Salary = 50000.0 WHERE LastName = 'Bieri' "); ... stmt.close(); Abteilung Informatik, JFC/Swing 2004 © Diego Schmidlin V2.2 K10_Datenanbindung-P.ppt, V2.2 2004 © Diego Schmidlin K10 Datenanbindung Folie 22 Seite 11 FHZ Hochschule Technik+Architektur Luzern Abteilung Informatik, Swing/JFC K10 Datenanbindung 2.4 ResultSet (1) • ResultSet – ist das Ergebnis einer SQL-Abfrage – enthält einen oder mehrere Records – bietet Methoden um auf Datenfelder zuzugreifen • Scrolling – ResultSet kann vorwärts/rückwärts durchlaufen werden – Auch sensitive ResultSets möglich (dynamische Sicht) • Updates – Tupel und Ergebnisse sind änderbar – Änderungen können sich auch auf Datenbank auswirken Abteilung Informatik, JFC/Swing 2004 © Diego Schmidlin V2.2 K10 Datenanbindung Folie 23 2.4 ResultSet (2) • Wichtigste Methoden Methode Beschreibung boolean next() Setzt den Cursol auf den ersten bzw. nächsten Record innerhalb von ResultSet boolean previous() Setzt den Cursol auf den vorhergehenden Record innerhalb von ResultSet (ab JDBC 2.0) boolean getBoolean(String name) Liefert den Wert des Feldes mit angegebenem name (case-insensitiv) int getInt(String name) Liefert den Wert des Feldes mit angegebenem name (case-insensitiv) float getFloat(String name) Liefert den Wert des Feldes mit angegebenem name (case-insensitiv) double getDouble(String name) Liefert den Wert des Feldes mit angegebenem name (case-insensitiv) String getString(String name) Liefert den Wert des Feldes mit angegebenem name (case-insensitiv) boolean getBoolean(int n) Liefert den Wert des n-ten Feldes (von 1 an gezählt) int getInt(int n) Liefert den Wert des n-ten Feldes (von 1 an gezählt) float getFloat(int n) Liefert den Wert des n-ten Feldes (von 1 an gezählt) double getDouble(int n) Liefert den Wert des n-ten Feldes (von 1 an gezählt) String getString(int n) Liefert den Wert des n-ten Feldes (von 1 an gezählt) Abteilung Informatik, JFC/Swing 2004 © Diego Schmidlin V2.2 K10_Datenanbindung-P.ppt, V2.2 2004 © Diego Schmidlin K10 Datenanbindung Folie 24 Seite 12 FHZ Hochschule Technik+Architektur Luzern Abteilung Informatik, Swing/JFC K10 Datenanbindung 2.4.1 ResultSet Typen (1) • Drei ResultSet Typen – vorwärts (TYPE_FORWARD_ONLY) • Navigation nur vorwärts möglich • Statische Sicht auf Daten – scroll-insensitive (TYPE_SCROLL_INSENSITIVE) • Navigation in beliebiger Richtung möglich • Statische Sicht auf Daten – scroll-sensitive (TYPE_SCROLL_SENSITIVE) • Navigation in beliebiger Richtung möglich • Änderungen auf der Datenbank sind sichtbar Abteilung Informatik, JFC/Swing 2004 © Diego Schmidlin V2.2 K10 Datenanbindung Folie 25 2.4.1 ResultSet Typen (2) • Zusätzlich Charakteristik von ResultSets – Änderbarkeit – Synchronisationsverhalten – nicht änderbar (CONCUR_READ_ONLY) • Keine Änderungen der Daten sind im ResultSet erlaubt – änderbar (CONCUR_UPDATABLE) • Änderungen erlaubt • Löschen erlaubt • Einfügen erlaubt Abteilung Informatik, JFC/Swing 2004 © Diego Schmidlin V2.2 K10_Datenanbindung-P.ppt, V2.2 2004 © Diego Schmidlin K10 Datenanbindung Folie 26 Seite 13 FHZ Hochschule Technik+Architektur Luzern Abteilung Informatik, Swing/JFC K10 Datenanbindung 2.4.2 Erzeugen von ResultSets (1) • Konstanten für ResultSet Typen Konstante Beschreibung static int TYPE_FORWARD_ONLY Navigation nur vorwärts möglich, statische Sicht auf Daten static int TYPE_SCROLL_INSENSITIVE Navigation in beliebiger Richtung möglich, statische Sicht auf Daten static int TYPE_SCROLL_SENSITIVE Navigation in beliebiger Richtung möglich, Änderungen erlaubt static int CONCUR_READ_ONLY Keine Änderungen der Daten sind im ResultSet erlaubt static int CONCUR_UPDATABLE Änderungen erlaubt, Update, Insert, Delete • Beispiel Statement stmt = con.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE); ResultSet rs = stmt.executeQuery("SELECT * FROM Employees"); Abteilung Informatik, JFC/Swing 2004 © Diego Schmidlin V2.2 K10 Datenanbindung Folie 27 2.4.2 Erzeugen von ResultSets (2) • Abfrage der Eigenschaften über Metadaten Methode Beschreibung boolean supportsResultSetType(int ResultSetType) Abfrage der unterstützten Typen boolean supportsResultSetConcurrency(int ResultSetType) Abfrage der Änderbarkeit • Abfrage der Eigenschaften beim ResultSet Methode Beschreibung int getType() Abfrage der unterstützten Typen int getConcurrency() Abfrage der Änderbarkeit Abteilung Informatik, JFC/Swing 2004 © Diego Schmidlin V2.2 K10_Datenanbindung-P.ppt, V2.2 2004 © Diego Schmidlin K10 Datenanbindung Folie 28 Seite 14 FHZ Hochschule Technik+Architektur Luzern Abteilung Informatik, Swing/JFC K10 Datenanbindung 2.4.3 Scrollen in ResultSets (1) • Scrollbare ResultSets in JDBC 2 erlauben freies Navigieren über die Ergebnismenge • Methoden zum Positionieren Methode Beschreibung void beforeFirst() Setzt Cursor vor das erste Tupel void afterLast() Setzt Cursor hinter das letzte Tupel boolean first() Setzt Cursor direkt auf das erste Tupel. False wenn keine Tupel vorhanden sind boolean last() Setzt Cursor direkt auf das letzte Tupel. False wenn keine Tupel vorhanden sind • Bei leerer Ergebnismenge liefert first(), last() das Ergebnis false • Initiale Position ist immer vor dem ersten Tupel Abteilung Informatik, JFC/Swing 2004 © Diego Schmidlin V2.2 K10 Datenanbindung Folie 29 2.4.3 Scrollen in ResultSets (2) • Cursor kann auch direkt auf ein bestimmtes Element gesetzt werden Methode Beschreibung boolean absolute(int row) Absolute Positionierung von 1 an gezählt boolean relative(int row) Relative Positionierung vom aktuellen Tupel aus • Aktuelle Position des Cursors Methode Beschreibung int getRow() Aktuelle, absolute Position des Cursors boolean isLast() True, wenn Cursor auf dem letzten Tupel steht boolean isFirst() True, wenn Cursor auf dem ersten Tupel steht boolean isAfterLast() True, wenn Cursor hinter dem letzten Tupel steht boolean isBeforeFirst() True, wenn Cursor vor dem ersten Tupel steht Abteilung Informatik, JFC/Swing 2004 © Diego Schmidlin V2.2 K10_Datenanbindung-P.ppt, V2.2 2004 © Diego Schmidlin K10 Datenanbindung Folie 30 Seite 15 FHZ Hochschule Technik+Architektur Luzern Abteilung Informatik, Swing/JFC K10 Datenanbindung 2.4.4 Updates in ResultSets • Methoden für Updates in ResultSets Methode Beschreibung void updateRow() Schreibt Inhalt der Zeile in die Datenbank void cancelRowUpdates() Macht Änderungen auf dem ResultSet rückgängig void updateBoolean(String columnName, boolean x) void updateBoolean(int columnIndex, boolean x) Setzt den Wert des Feldes (name case-insensitiv) Setzt den Wert des Feldes (Index) void updateInt(String columnName, int x) void updateInt(int columnIndex, int x) Setzt den Wert des Feldes (name case-insensitiv) Setzt den Wert des Feldes (Index) void updateLong(String columnName, long x) void updateLong(int columnIndex, long x) Setzt den Wert des Feldes (name case-insensitiv) Setzt den Wert des Feldes (Index) void updateFloat(String columnName, float x) void updateFloat(int columnIndex, float x) Setzt den Wert des Feldes (name case-insensitiv) Setzt den Wert des Feldes (Index) void updateDouble(String columnName, double x) void updateDouble(int columnIndex, double x) Setzt den Wert des Feldes (name case-insensitiv) Setzt den Wert des Feldes (Index) void updateString(String columnName, String x) void updateString(int columnIndex, String x) Setzt den Wert des Feldes (name case-insensitiv) Setzt den Wert des Feldes (Index) Abteilung Informatik, JFC/Swing 2004 © Diego Schmidlin V2.2 K10 Datenanbindung Folie 31 2.4.4 Updates in ResultSets: Beispiel • Änderung an einem bestehenden Tupel ResultSet rs = stmt.executeQuery("SELECT * FROM Employees"); if(rs.first()) { rs.updateInt("BirthYear", 1972); rs.updateRow(); } stmt.close(); Abteilung Informatik, JFC/Swing 2004 © Diego Schmidlin V2.2 K10_Datenanbindung-P.ppt, V2.2 2004 © Diego Schmidlin K10 Datenanbindung Folie 32 Seite 16 FHZ Hochschule Technik+Architektur Luzern Abteilung Informatik, Swing/JFC K10 Datenanbindung 2.4.5 Einfügen in ResultSets • Das Einfügen eines Tuples erfolgt an einer speziellen Einfügeposition • Die Einfügeposition wird mit der Methode moveToInsertRow() erreicht • Die Einfügeposition wird anschliessend über die updateXXX()-Methoden mit Werten belegt • Zum Schluss werden diese mit insertRow() gespeichert • Beim Wechsel zur Einfügeposition merkt sich das ResultSet die aktuelle Cursor-Position • Nach dem Einfügen kann mit der Methode moveToCurrentRow() zurückgesprungen werden Abteilung Informatik, JFC/Swing 2004 © Diego Schmidlin V2.2 K10 Datenanbindung Folie 33 2.4.5 Einfügen in ResultSets: Beispiel • Neues Tupel einfügen ResultSet rs = stmt.executeQuery("SELECT * FROM Employees"); if(rs.absolute(10)) { rs.moveToInsertRow(); // Move to special row for inserts rs.updateString("FirstName", "Freddy"); rs.updateString("LastName", "Schnell"); rs.updateInt("BirthYear", 1981); rs.updateFloat("Salary", 65100.0); rs.insertRow(); //Zurück zu Tupel #10 rs.moveToCurrentRow(); // Move back to current row } stmt.close(); Abteilung Informatik, JFC/Swing 2004 © Diego Schmidlin V2.2 K10_Datenanbindung-P.ppt, V2.2 2004 © Diego Schmidlin K10 Datenanbindung Folie 34 Seite 17 FHZ Hochschule Technik+Architektur Luzern Abteilung Informatik, Swing/JFC K10 Datenanbindung 2.4.6 Löschen in ResultSets • Zum Löschen eines Tuples aus einem ResultSet muss der Cursor entsprechend positioniert werden • Anschliessend kann das Tupel durch Aufruf von deleteRow() gelöscht werden • Ob das Tupel physisch aus dem ResultSet gelöscht wird oder nur als gelöscht markiert wird, ist von der Implementierung des Treibers abhängig • Alle Änderungen über ResultSets lassen sich natürlich auch mit SQL-Operationen ausführen – Nicht alle Anfragen führen zu änderbaren ResultSets – Änderungen über ResultSets sind mehr für interaktive Anwendungen geeignet Abteilung Informatik, JFC/Swing 2004 © Diego Schmidlin V2.2 K10 Datenanbindung Folie 35 2.4.6 Löschen in ResultSets: Beispiel • Tupel löschen ResultSet rs = stmt.executeQuery("SELECT * FROM Employees"); if(rs.absolute(10)) { rs.deleteRow(); rs.absolute(10)) } stmt.close(); Abteilung Informatik, JFC/Swing 2004 © Diego Schmidlin V2.2 K10_Datenanbindung-P.ppt, V2.2 2004 © Diego Schmidlin K10 Datenanbindung Folie 36 Seite 18 FHZ Hochschule Technik+Architektur Luzern Abteilung Informatik, Swing/JFC K10 Datenanbindung 2.4.7 Limiten für ResultSets (1) • Die meisten Treiber limitieren die Anzahl der Datensätze innerhalb eines ResultSets • Diese maximale erlaubte Anzahl Datensätze kann auf dem Statement–Objekt erfragt und konfiguriert werden int max = myStatement.getMaxRows(); myStatement.setMaxRows(1000); • Die Limitierung kann auch wieder aufgehoben werden myStatement.setMaxRows(0); Abteilung Informatik, JFC/Swing 2004 © Diego Schmidlin V2.2 K10 Datenanbindung Folie 37 2.4.7 Limiten für ResultSets (2) • Es gibt auch Feld-Typen, welche eine grosse Anzahl an binären Daten aufnehmen können – BINARY Fields – BLOB (Binary Large Object, SQL-99) – CLOB (Character Large Object, SQL-99) • Die Limitierung der Feldgrösse kann auf dem Statement– Objekt erfragt und konfiguriert werden int max = myStatement.getMaxFieldSize(); myStatement.setMaxFieldSize(4096); • Die Limitierung kann auch wieder aufgehoben werden myStatement.setMaxFieldSize(0); Abteilung Informatik, JFC/Swing 2004 © Diego Schmidlin V2.2 K10_Datenanbindung-P.ppt, V2.2 2004 © Diego Schmidlin K10 Datenanbindung Folie 38 Seite 19 FHZ Hochschule Technik+Architektur Luzern Abteilung Informatik, Swing/JFC K10 Datenanbindung 3.1.1 ResultSet TableModel: Version 1 (1) • Version 1 mit Daten-Vektor class ResultSetModel1 extends AbstractTableModel { private private private private private private ResultSet rs; // Ref to ResultSet int cols; // nbr of columns in rs int rows; // nbr of rows in rs ResultSetMetaData rsmd; // Ref to Metadata Vector vRows = new Vector(); // Data-Vector String[] columnNames = new String[0]; Abteilung Informatik, JFC/Swing 2004 © Diego Schmidlin V2.2 K10 Datenanbindung Folie 39 3.1.1 ResultSet TableModel: Version 1 (2) public int getColumnCount() { return cols ; } public String getColumnName(int col) { return columnNames[col]; } public int getRowCount() { return vRows.size(); } public Object getValueAt(int row, int col) { Vector vOneRow = (Vector) vRows.elementAt(row); return vOneRow.elementAt(col); } Abteilung Informatik, JFC/Swing 2004 © Diego Schmidlin V2.2 K10_Datenanbindung-P.ppt, V2.2 2004 © Diego Schmidlin K10 Datenanbindung Folie 40 Seite 20 FHZ Hochschule Technik+Architektur Luzern Abteilung Informatik, Swing/JFC K10 Datenanbindung 3.1.1 ResultSet TableModel: Version 1 (3) public void setResultSet(ResultSet rs) { try { rsmd = rs.getMetaData(); // build a string array of column names cols = rsmd.getColumnCount(); columnNames = new String[cols]; for(int i = 0; i < cols; i++) { columnNames[i] = rsmd.getColumnLabel(i + 1); } Abteilung Informatik, JFC/Swing 2004 © Diego Schmidlin V2.2 K10 Datenanbindung Folie 41 3.1.1 ResultSet TableModel: Version 1 (4) // build data vector of vectors while(rs.next()) { Vector vOneRow = new Vector(); for(int i = 0; i < cols; i++) { vOneRow.addElement(rs.getString(i + 1)); } vRows.addElement(vOneRow) ; } fireTableChanged(null) ; // tell JTable to update } catch (SQLException sqle) {} } } Abteilung Informatik, JFC/Swing 2004 © Diego Schmidlin V2.2 K10_Datenanbindung-P.ppt, V2.2 2004 © Diego Schmidlin K10 Datenanbindung Folie 42 Seite 21 FHZ Hochschule Technik+Architektur Luzern Abteilung Informatik, Swing/JFC K10 Datenanbindung 3.1.2 ResultSet TableModel: Version 2 (1) • Version 2 mit direktem Zugriff auf ResultSet class ResultSetModel2 extends AbstractTableModel { private private private private ResultSet rs; // Ref to ResultSet int cols; // nbr of columns in rs ResultSetMetaData rsmd; // Ref to Metadata String[] columnNames = new String[0]; public int getColumnCount() { return cols; } public String getColumnName(int col) { return columnNames[col]; } Abteilung Informatik, JFC/Swing 2004 © Diego Schmidlin V2.2 K10 Datenanbindung Folie 43 3.1.2 ResultSet TableModel: Version 2 (2) public int getRowCount() { if (rs == null) return 0; try { rs.last(); return rs.getRow(); } catch (SQLException sqle) { return 0; } } public Object getValueAt(int row, int col) { try { rs.absolute(row + 1); return rs.getString(col + 1); } catch ( SQLException sqle ) { return null ; } } Abteilung Informatik, JFC/Swing 2004 © Diego Schmidlin V2.2 K10_Datenanbindung-P.ppt, V2.2 2004 © Diego Schmidlin K10 Datenanbindung Folie 44 Seite 22 FHZ Hochschule Technik+Architektur Luzern Abteilung Informatik, Swing/JFC K10 Datenanbindung 3.1.2 ResultSet TableModel: Version 2 (3) public Class getColumnClass( int col ) { String className = new String(); try { className = rsmd.getColumnClassName(col); } catch (SQLException e) { } if (className.endsWith("String")) return String.class; else if(className.endsWith("Boolean")) return Boolean.class; else if(className.endsWith("Short")) return Short.class; else if(className.endsWith("Integer")) return Integer.class; else if(className.endsWith("Long")) return Long.class; else if(className.endsWith("Double")) return Double.class; else if(className.endsWith("Date")) return java.sql.Date.class; else return Object.class; } Abteilung Informatik, JFC/Swing 2004 © Diego Schmidlin V2.2 K10 Datenanbindung Folie 45 3.1.2 ResultSet TableModel: Version 2 (4) public void setResultSet(ResultSet rs) { this.rs = rs; // set the table model's data source try { rsmd = rs.getMetaData(); // build a string array of column names cols = rsmd.getColumnCount(); columnNames = new String[cols]; for(int i = 0; i < cols; i++) { columnNames[i] = rsmd.getColumnLabel(i + 1); } fireTableChanged(null); // tell JTable to update } catch(SQLException sqle) {} } } Abteilung Informatik, JFC/Swing 2004 © Diego Schmidlin V2.2 K10_Datenanbindung-P.ppt, V2.2 2004 © Diego Schmidlin K10 Datenanbindung Folie 46 Seite 23 FHZ Hochschule Technik+Architektur Luzern Abteilung Informatik, Swing/JFC K10 Datenanbindung 3.2 JTable: Editieren • • 1. 2. Wenn das TableModel von der Klasse AbstractTableModel abgeleitet wird, so sind die Zellen read-only So werden die Zellen editierbar gemacht: JTable myTable = new JTable(myTableModel); myTable.setCellSelectionEnabled(true); public boolean isCellEditable(int row, int col) { // lock first column if (col == 0) return false; return true; //otherwise can edit } Abteilung Informatik, JFC/Swing 2004 © Diego Schmidlin V2.2 K10 Datenanbindung Folie 47 3.2 JTable: Editieren: Version 1 • Version 1 mit Daten-Vektor public void setValueAt(Object value, int row, int try { vOneRow = (Vector)vRows.elementAt(row); vOneRow.setElementAt(value, col); vRows.setElementAt(vOneRow, row); col){ // SQL UPDATE um Daten in Datenbank zu schreiben ... } catch (SQLException e) {} } Abteilung Informatik, JFC/Swing 2004 © Diego Schmidlin V2.2 K10_Datenanbindung-P.ppt, V2.2 2004 © Diego Schmidlin K10 Datenanbindung Folie 48 Seite 24 FHZ Hochschule Technik+Architektur Luzern Abteilung Informatik, Swing/JFC K10 Datenanbindung 3.2 JTable: Editieren: Version 2 • Version 2 mit direktem Zugriff auf ResultSet public void setValueAt(Object value, int row, int try { rs.absolute(row + 1); col){ // Strings only, need other code for other types rs.updateString(col + 1, value.toString()); rs.updateRow(); // where supported } catch (SQLException e) {} } K10_Datenanbindung-P.ppt, V2.2 2004 © Diego Schmidlin Abteilung Informatik, JFC/Swing 2004 © Diego Schmidlin V2.2 K10 Datenanbindung Folie 49 Abteilung Informatik, JFC/Swing 2004 © Diego Schmidlin V2.2 K10 Datenanbindung Folie 50 Seite 25 FHZ Hochschule Technik+Architektur Luzern Abteilung Informatik, Swing/JFC K10 Datenanbindung Zusammenfassung • Beim Einlesen von Text-Files können einzelne Felder durch StringTokanizer oder StreamTokanizer isoliert werden • Bei der Objekt-Serialisierung werden ObjektZustände gesprichert/gelesen – Speichern/ Einlesen von Instanzvariablen • Um ein Objekt serialisierbar zu machen genügt es, das Marker-Interface Serializable zu "implementieren" • Mit dem Modifier transient wird das Serialisieren einzelner Instanzvariablen unterdrückt Abteilung Informatik, JFC/Swing 2004 © Diego Schmidlin V2.2 K10 Datenanbindung Folie 51 Zusammenfassung • Ab JDBC 2 sind Scrolling und Updates direkt auf ResultSets möglich • Änderungen in Result-Sets beziehen sich immer auf das Tupel an der aktuellen Cursor-Position • Das Einfügen eines Tuples erfolgt an einer speziellen Einfügeposition • Zum Löschen eines Tuples aus einem ResultSet muss der Cursor entsprechend positioniert werden • ResultSet und TableModel lassen sich kombinieren: – statische Sicht auf Datenbank – dynamische sicht auf die Datenbank Abteilung Informatik, JFC/Swing 2004 © Diego Schmidlin V2.2 K10_Datenanbindung-P.ppt, V2.2 2004 © Diego Schmidlin K10 Datenanbindung Folie 52 Seite 26