Vorlesung Informatik II Universität Augsburg Wintersemester 2011/2012 Prof. Dr. Bernhard Bauer Folien von: Prof. Dr. Robert Lorenz Lehrprofessur für Informatik 10. Java: Datenhaltung mit Datenbanken 1 Datenbank-Programme Derby (Hersteller: Apache Foundation) Für die lokale Installation auf ihrem Rechner Download von Datenbank und Treiber (jar-Datei): http://db.apache.org/derby/ Datei entpacken und Pfad merken Pfad im Classpath eintragen: java –Xbootclasspath/a: <Pfad der jar-Datei> Beim ersten Programmstart muss man Tabellen erzeugen (create-Anweisung) Bei erneutem Start stehen diese Tabellen zur Verfügung. 2 Datenbank-Programme MySQL Haben wir auf unserem Server installiert (aiomr.informatik.uni-augsburg.de): Nur erreichbar über Uni-Netz oder VPN-Verbindung Download des Treibers (jar-Datei): http://www.mysql.com/products/connector/j/ Datei entpacken und Pfad merken Als externe jar-Datei in Eclipse-Projekt eintragen Tabellen zum Abfragen sind angelegt (keine neuen Tabellen anlegen!) 3 ODBC - Schnittstelle Open Database Connectivity (ODBC) Für alle kommerziellen und freien DBMS gibt es die einheitliche, standardisierte Benutzerschnittstelle ODBC ODBC verwendet SQL Der ODBC-Treiber eines DBMS bietet eine ProgrammierSchnittstelle (API) für C-Programme Über ODBC kann eine Anwendung eine Datenbank unabhängig von ihrer Implementierung über SQL-Befehle verwaltet werden 4 JDBC - Schnittstelle Java Database Connectivity (JDBC) Für den Zugriff über Java-Programme existiert die entsprechende Schnittstelle JDBC Das Paket java.sql stellt Klassen für den Zugriff auf Datenbanken über ihre JDBC-Schnittstelle bereit Über diese Schnittstelle können wir einheitlich sowohl auf die Derby-, als auch auf die MySQL-Datenbank zugreifen! 5 Das Paket java.sql Schritt 1: Laden einer JDBC-Treiber-Klasse (DB-spezifisch) Klassenoperation der Klasse Class: static Class forName(String className) A call to forName("X") causes the class named X to be initialized Returns: Class object for the class with the specified name. className fully qualified name of the desired class. Class Metaklasse zur Verwaltung von Datentypen 6 Das Paket java.sql Schritt 1: Laden einer JDBC-Treiber-Klasse (DB-spezifisch) Class.forName( “org.apache.derby.jdbc.EmbeddedDriver”); Class.forName(“com.mysql.jdbc.Driver”); 7 Das Paket java.sql Schritt 2: Verbindung zur DB herstellen (DB-spezifisch) Klassenoperation der Klasse DriverManager static Connection getConnection(String url, String User, String password) Attempts to establish a connection to the given database URL. Attempts to select a driver from the set of registered JDBC drivers. url DriverManager a database url of the form jdbc:subprotocol:subname Verwaltet geladene Treiber-Klassen 8 Das Paket java.sql Schritt 2: Verbindung zur DB herstellen (DB-spezifisch) Connection c = DriverManager.getConnection( “jdbc:derby:derbyDB;create=true”,””,””); Connection c = DriverManager.getConnection( “jdbc:mysql://aiomr.informatik.uni-augsburg.de: 3306/theDatabase”,”user”,”password”); 9 Das Paket java.sql Schritt 3: Anweisungs-Objekt für SQL-Anfragen (einheitlich!) Operation der Schnittstelle Connection Statement createStatement() Creates a Statement object for sending SQL statements to the database. Connection A connection (session) with a specific database. SQL statements are executed within the context 10 Das Paket java.sql Schritt 3: Anweisungs-Objekt für SQL-Anfragen (einheitlich!) Statement abfrage = c.createStatement(); 11 Das Paket java.sql Schritt 4: SQL-Anweisung ausführen (einheitlich!) Operationen der Schnittstelle Statement ResultSet executeQuery(String query) executes the given SQL statement, returns a single ResultSet object. ResultSet contains the data produced by the given query; never null Statement The object used for executing a static SQL statement and returning the results it produces. 12 Das Paket java.sql Schritt 4: SQL-Anweisung ausführen (einheitlich!) Operationen der Schnittstelle Statement boolean execute(String sql) executes the given SQL statement, which may return multiple results. use getResultSet,getMoreResults to get the result(s). 13 Das Paket java.sql Schritt 4: SQL-Anweisung ausführen (einheitlich!) Operationen der Schnittstelle Statement int executeUpdate(String sql) executes INSERT, UPDATE, or DELETE statements Returns: the row count for statement 14 Das Paket java.sql Schritt 4: SQL-Anweisung ausführen (einheitlich!) Operationen der Schnittstelle Statement ResultSet getResultset() Returns data from previous execute 15 Das Paket java.sql Schritt 4: SQL-Anweisung ausführen (einheitlich!) Operationen der Schnittstelle Statement void close() Releases database and JDBC resources 16 Das Paket java.sql Tabelle kreieren: String befehl = “CREATE TABLE ‘Vorlesung’ ( ‘ID’ INTEGER NOT NULL, ‘Name’ VARCHAR(20) NOT NULL, ‘Jahr’ CHAR(4) NOT NULL, ‘Semester’ CHAR(2) NOT NULL, ‘DozentID’ INTEGER)”; abfrage.execute(befehl); (Hochkommas bei Bezeichnern, Unterscheidung Gross/KleinSchreibung) 17 Das Paket java.sql Tupel einfügen: String befehl = “INSERT INTO Vorlesung VALUES (1,‘Informatik 2‘,‘2009‘,‘SS‘,null)”; abfrage.executeUpdate(befehl); (Hochkommas bei Zeichenketten, nicht bei Zahlen, nicht bei null) 18 Das Paket java.sql Tupel löschen: String befehl = “DELETE FROM Vorlesung WHERE semester = ‘SS’”; abfrage.executeUpdate(befehl); 19 Das Paket java.sql Tupel ändern: String befehl = “UPDATE Vorlesung SET DozentID = 13 WHERE ID = 1”; abfrage.executeUpdate(befehl); 20 Das Paket java.sql Tupel ausgeben: String befehl = “SELECT * FROM Vorlesung”; ResultSet ergebnis = abfrage.executeQuery(befehl); 21 Das Paket java.sql Tupel ausgeben: Schnittstelle ResultSet A table of data representing a database result set Maintains a cursor pointing to its current row of data (initially 1st row) Default: not updatable, has a cursor that moves forward only. 22 Das Paket java.sql Tupel ausgeben: Schnittstelle ResultSet Vorwärts/Rückwärts durchlaufbar und aktualisierbar machen durch Aufruf anderer Version von createStatement unter Benutzung geeigneter Konstanten: Statement stmt = c.createStatement( ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE); ResultSet rs=stmt.executeQuery("..."); 23 Das Paket java.sql Tupel ausgeben: Schnittstelle ResultSet Operationen zur Positionierung des Cursors: boolean absolute(int row) void moveToInsertRow() void moveToCurrentRow() boolean first() boolean last() boolean next() boolean previous() 24 Das Paket java.sql Tupel ausgeben: Schnittstelle ResultSet Operationen, um Daten zu lesen (für jeden Datentyp): boolean getBoolean(int columnIndex) boolean getBoolean(String columnName) ... 25 Das Paket java.sql Tupel ausgeben: Schnittstelle ResultSet Operationen, um Daten zu aktualisieren (für jeden Datentyp): void ... void void void updateBoolean(int columnIndex, boolean x) insertRow() updateRow() deleteRow() 26 Das Paket java.sql Tupel ausgeben: String befehl = “SELECT * FROM Vorlesung”; ResultSet ergebnis = abfrage.executeQuery(befehl); while (ergebnis.next()){ System.out.println(ergebnis.getString(“Name”)); //oder Operationen zum Erzeugen von Objekten } 27 Das Paket java.sql Zusammenfassung des Codes: Class.forName(“org.apache.derby.jdbc.EmbeddedDriver”); Connection c = DriverManager.getConnection( “jdbc:derby:derbyDB;create=true”,””,””); Statement abfrage = c.createStatement(); String befehl = “SELECT * FROM Vorlesung”; ResultSet ergebnis = abfrage.executeQuery(befehl); while (ergebnis.next()){ //Operationen zum Erzeugen von Objekten } 28 Das Paket java.sql Zusammenfassung des Codes: Programmabbruch bei Fehler Klasse nicht vorhanden Class.forName(“org.apache.derby.jdbc.EmbeddedDriver”); Connection c = DriverManager.getConnection( Kein Treiberzugriff “jdbc:derby:derbyDB;create=true”,””,””); Statement abfrage = c.createStatement(); String befehl = “SELECT * FROM Vorlesung”; ResultSet ergebnis = abfrage.executeQuery(befehl); Kein while (ergebnis.next()){ //Operationen zum ErzeugenDatenbankzugriff von Objekten } 29 Das Paket java.sql Zusammenfassung des Codes: Fehler abfangen try{ Class.forName(“org.apache.derby.jdbc.EmbeddedDriver”); Connection c = DriverManager.getConnection( “jdbc:derby:derbyDB;create=true”,””,””); Statement abfrage = c.createStatement(); String befehl = “SELECT * FROM Vorlesung”; ResultSet ergebnis = abfrage.executeQuery(befehl); while (ergebnis.next()){ //Operationen zum Erzeugen von Objekten } }catch(Exception e){<Code für Fehlerbehandlung>} 30 Das Paket java.sql Einfügen in Datenhaltungsschicht: Klassendiagramm <Container> daten<Container> root DatenContainer root <Container> store <<interface>> Datenhaltung daten<Container> Datei 31 Das Paket java.sql Einfügen in Datenhaltungsschicht: Klassendiagramm + + + + + <<interface>> Datenhaltung load save add delete modify Laden und Speichern aller Objekte Speichern, Löschen und Modifizieren einzelner Objekte 32 Das Paket java.sql Einfügen in Datenhaltungsschicht (eine Alternative): Klassendiagramm Datei - DriverClassName :String =... - databaseUrl :String =... con :Connection user :String password :String + + + + + + Datei() load(out con :DatenContainer) save(in con :DatenContainer) add(in o :Object) delete(in o :Object) modify(in o :Object) 33 Das Paket java.sql Einfügen in Datenhaltungsschicht (eine Alternative): Implementierung in Java public Datei() { try{ Class.forName(driverClassName); con = DriverManager.getConnection (databaseUrl,user,password); }catch(Exception e){ <Code für Fehlerbehandlung> } } 34 Das Paket java.sql Einfügen in Datenhaltungsschicht (eine Alternative): Implementierung in Java public void load(DatenContainer con){ try{ Statement abfrage = con.createStatement(); String befehl = <Select-Ausdruck passend zu Klasse>; ResultSet ergebnis = abfrage.executeQuery(befehl); while (ergebnis.next()){ <Objekte erzeugen in Containern über dataCon> } }catch(Exception e){ <Code für Fehlerbehandlung> } } [Bei mehreren Klassen: viele select-Anweisungen nacheinander] 35 Das Paket java.sql Daten aus Datenbank laden AnwendungsGUI starten In AnwendungsGUI DatenContainer initialisieren In DatenContainer Objekt-Container initialisieren In DatenContainer Datei-Objekt store initialisieren und store.load(this) aufrufen 36 Das Paket java.sql Einfügen in Datenhaltungsschicht (eine Alternative): Implementierung in Java public void add(Oblect o){ try{ Statement abfrage = con.createStatement(); String befehl = <insert-Ausdruck passend zu o>; abfrage.executeUpdate(befehl); }catch(Exception e){ <Code für Fehlerbehandlung> } } [Bei mehreren Klassen: Viele alternative insert-Anweisungen] 37 Das Paket java.sql Neues Objekt in Datenbank speichern “Speichern”-Button klicken In actionPerformed(): Objekt erzeugen und in ObjektContainer einfügen Im Container: Aufruf von root.getStore().add(o) 38 Das Paket java.sql Verwaltung der Werte der (zusätzlichen) ID-Spalten? Zusätzliche ID-Attribute in den Fachkonzeptklassen (Vor-/Nachteile?) Übernehmen der Werte beim Laden/Abspeichern Wie stellt man die Eindeutigkeit der ID-Werte sicher? ID-Attribut in der Fachkonzeptschicht verwenden? Identifizieren von Tupeln in Tabellen über die ID 39 Das Paket java.sql Verwaltung der Werte der (zusätzlichen) ID-Spalten? Keine solchen zusätzlichen Attribute (Vor-/Nachteile?) Erzeugung der Werte beim Abspeichern (Datenhaltung) Ignorieren der ID-Werte beim Laden Wie identifiziert man Tupel in Tabellen? Wie stellt man die Eindeutigkeit der ID-Werte sicher? 40