Programmierkurs – Kapitel 2 Dipl.-Wirt.-Inf. Stefan Fleischer Dipl.-Wirt.-Inf. Ulrich Wolffgang Programmierkurs Komponente: Persistierung Interface für Persistenzschicht entwickeln import java.net.URL; import java.util.ArrayList; public interface IDatabase { public void saveEmailAddresses(ArrayList<String> emailaddresses) throws Exception; public void saveUrls(ArrayList<URL> urls) throws Exception; public void setUrlVisited(URL url) throws Exception; public URL getRandomUrl() throws Exception; } Programmierkurs 1 Entwicklungsfolie für die Tafel Datenbanksystem Problem: Java-Programm verliert Speicherwerte nach Beendigung des Programms Lösung: Zur Persistierung wird ein dauerhafter Speicher benutzt eine Datenbank Verbreitete Datenbanksysteme: PostgreSQL, MySQL, MSQL, Oracle Database, SQLite Auswahlkriterien Lizenz Nutzbarkeit, Preis Dokumentation Best-Practices Verbreitung Dokumentation, Unterstützung in Foren Technisch Performance, Datensicherheit, Standardabdeckung Toolsupport Interaktion mit DBS ermöglichen Programmierkurs 2 MySQL Für den Kurs wird MySQL genutzt GPL als Lizenz Dokumentation unter www.mysql.com Verbreitung sehr hoch, vor allem bei dynamischen Websites Technisch: zuverlässig, Performance OK für unsere Zwecke, unterstützt SQL1999/SQL3 Toolsupport sehr gut: MySQL Admin, MySQL Query Browser, mysqldump, phpMyAdmin, … Download des Community Server: www.mysql.com Installationsprozess zeigen (UTF8) Tools zeigen Programmierkurs 3 Installation eines MySQL Community Servers Programmierkurs 4 Installation eines MySQL Community Servers Programmierkurs 5 Installation eines MySQL Community Servers Programmierkurs 6 Installation eines MySQL Community Servers Programmierkurs 7 Konfiguration des MySQL Community Servers Programmierkurs 8 Konfiguration des MySQL Community Servers Programmierkurs 9 Konfiguration des MySQL Community Servers Programmierkurs 10 Konfiguration des MySQL Community Servers Programmierkurs 11 Konfiguration des MySQL Community Servers Programmierkurs 12 Konfiguration des MySQL Community Servers Programmierkurs 13 Konfiguration des MySQL Community Servers Programmierkurs 14 Konfiguration des MySQL Community Servers Programmierkurs 15 Konfiguration des MySQL Community Servers Programmierkurs 16 Konfiguration des MySQL Community Servers Programmierkurs 17 MySQL Tools MySQL Administrator MySQL Query Browser Programmierkurs 18 MySQL User Account Management User haben Zugriffsrechte auf Datenbanken/Tabellen/Spalten und damit auf Datensätze Account: Name, Passwort Resource-Limits SSL-Connections Beispiel: Neuen Nutzer anlegen GRANT SELECT, INSERT, UPDATE ON db.* TO ‚username‘@‚localhost‘ IDENTIFIED BY ‚password‘; flush privileges; Auf „ernstzunehmenden“ Produktivsystemen sollte die reguläre Interaktion nicht mit root-Rechten erfolgen! Programmierkurs 19 MySQL-Treiber für Java bekannt machen Problem: Java Virtual Machine muss wissen, wo MySQL-Treiber zu finden ist Lösung: Java-Classpath Pfadangabe für Java Virtual Machine, wo beim Ausführen von JavaProgrammen nach Klassen und Paketen gesucht werden soll. Classpath soll auf MySQL-Treiber zeigen. Alternative 1: Systemweit Auf der Konsole (Eingabeaufforderung ) eingeben: set CLASSPATH=% CLASSPATH%; C:\mysql-connector-java-5.1.5bin.jar; Alternative 2 für den Kurs: Eclipse-Projekt-weit MySQL-Treiber in Eclipse-Project auf folgende Weise dem Classpath hinzufügen: Programmierkurs 20 MySQL-Treiber für Java bekannt machen Programmierkurs 21 MySQL-Treiber für Java bekannt machen Programmierkurs 22 Datenmanagement SQL Funktionalität auf Metadaten Create: CREATE DATABASE dbname; Create: CREATE TABLE tblname (id INT, …); Read: SHOW TABLES; Update: ALTER TABLE tblname CHANGE …; Delete: DROP TABLE tblname; Funktionalität auf Datensätzen Create: INSERT INTO tblname (colname, …) VALUES („wert“, …); Read: SELECT expr FROM tblnames WHERE wherecond; Update: UPDATE tblname SET (colname=„wert“, …); Delete: DELETE FROM tblname WHERE wherecond; PRIMARY KEY, INDEX, UNIQUE (für URLs) Programmierkurs 23 MySQL-Typen In den Tabellen der Datenbank ist jede Spalte typisiert Einige MySQL-Typen: INT: Zahl zwischen -2147483648 und 2147483647 TINYINT: Zahl zwischen -128 und 127 VARCHAR(M): String der maximalen Länge von M Zeichen, z. B. VARCHAR(255) CHAR(M): String der Länge von M Zeichen, z. B. CHAR(255) TEXT: Text mit maximaler Länge 65535 DATETIME: Datum im Format ‚YYYY-MM-DD HH:MM:SS‘, z. B. 2012-12-31 23:59:59 Programmierkurs 24 Datenmanagement SQL CREATE TABLE person (id INT NOT NULL AUTO_INCREMENT, name VARCHAR(255) NOT NULL, PRIMARY KEY (id) ) ENGINE = MYISAM CHARACTER SET utf8 COLLATE utf8_general_ci; INTEGER id VARCHAR(255) name ALTER TABLE person CHANGE name vorname VARCHAR(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL; INTEGER id VARCHAR(255) vorname INSERT INTO person (vorname) VALUES ("Charlie"); INTEGER id VARCHAR(255) vorname 1 Charlie Programmierkurs 25 Datenmanagement SQL INSERT INTO person (vorname) VALUES ("John"); INTEGER id VARCHAR(255) vorname 1 Charlie 2 John Feld id wird automatisch inkrementiert. UPDATE person SET vorname = "Stephen" WHERE person.id = 1; INTEGER id VARCHAR(255) vorname 1 Stephen 2 John Programmierkurs 26 Datenmanagement SQL SELECT * FROM person WHERE vorname = "Stephen" LIMIT 0,30; SELECT * FROM person WHERE vorname LIKE "Ste%" LIMIT 0,30; INTEGER id vorname 1 Stephen DELETE FROM person WHERE person.id = 2; INTEGER id VARCHAR(255) vorname 1 Stephen 2 John DROP TABLE person; INTEGER id VARCHAR(255) vorname 1 Stephen Programmierkurs 27 Datenstrukturen und Algorithmen Index Warum Indexe? Schnelleres Finden von Datensätzen bestimmter Spaltenwerte Entsprechende Spalte muss indiziert sein Bei 1000 Datensätzen ist die Suche über einen Index ca. 100 mal schneller als die sequentielle Suche Verschiedene Index-Arten: Index allgemein (INDEX): Beschleunigt Suche auf Feldern CREATE TABLE person (id INT NOT NULL AUTO_INCREMENT, name VARCHAR(255) NOT NULL, PRIMARY KEY (id), INDEX namensindex (name) ) ENGINE = MYISAM CHARACTER SET utf8 COLLATE utf8_general_ci; Indexe mit erweiterter Semantik: Primärschlüssel (PRIMARY KEY), Eindeutiger Index (UNIQUE), Index zur Volltextsuche (FULLTEXT) Programmierkurs 28 Datenmanagement Datenbank fachkonzeptionell: ERM Datenmodell der Datenbank URL E-MailAdresse Programmierkurs 29 (0,m) (1,m) Datenmanagement Datenbank Implementierung: SQL Auf Verbindung zwischen URL und Emailaddresse (Relationshiptyp) hier verzichtet Vorlesung Datenmanagement CREATE TABLE url ( tld CHAR(5) NOT NULL, sld VARCHAR(255) NOT NULL, uld VARCHAR(255) DEFAULT NULL, visited TINYINT(4) NOT NULL DEFAULT '0', PRIMARY KEY (sld,tld), INDEX visited (visited) ) ENGINE=MyISAM DEFAULT CHARSET=utf8; CREATE TABLE emailaddress ( emailaddress VARCHAR(255) NOT NULL, PRIMARY KEY (emailaddress) ) ENGINE=MyISAM DEFAULT CHARSET=utf8; Programmierkurs 30 Entwicklungsfolie für die Tafel JDBC Java Database Connectivity Datenbankschnittstelle der Java-Plattform für einheitlichen Zugriff auf Datenbanken verschiedener Hersteller. Ermöglicht, Datenbankverbindungen aufzubauen, abzubauen, SQLAnfragen an Datenbank zu stellen. Setzt für jede spezifische Datenbank Treiber voraus. Beispiel: Verbindung zur MySQL-Server aufbauen import java.sql.*; //Nicht com.mysql.jdbc String url = "jdbc:mysql://" + host + "/" + database; Class.forName("com.mysql.jdbc.Driver").newInstance(); Connection connection = DriverManager.getConnection(url, username, password); Programmierkurs 31 JDBC Beispiel: SELECT eine Zeile Statement s = connection.createStatement(); s.executeQuery("SELECT id, name FROM animal LIMIT 0,1"); //eine Zeile anfragen ResultSet rs = s.getResultSet(); rs.next (); int idVal = rs.getInt("id"); String nameVal = rs.getString("name"); rs.close(); s.close(); Beispiel: SELECT mehrere Zeilen Statement s = connection.createStatement(); s.executeQuery("SELECT id, name FROM animal"); //alle Zeilen anfragen ResultSet rs = s.getResultSet(); while (rs.next ()) { //über Datensätze iterieren int idVal = rs.getInt("id"); String nameVal = rs.getString("name"); } rs.close(); s.close(); Programmierkurs 32 JDBC Beispiel: INSERT eine Zeile String cmd = "INSERT INTO animal (name) VALUES (?)"; PreparedStatement s = connection.prepareStatement(cmd); s.setString(1, name); s.executeUpdate(); s.close(); Beispiel: UPDATE alle Zeilen, auf die WHERE passt String cmd = "UPDATE animal SET name = ‘Lion’ WHERE name = ? AND age > ?"; PreparedStatement s = connection.prepareStatement(cmd); s.setString(1, „Cat“); s.setInt(2, age); s.executeUpdate(); s.close(); Programmierkurs 33 SQL Injection Einschleusen von Datenbankbefehlen Problem: Fehlende Maskierung von Benutzereingaben Benutzereingaben http://webserver/find.cgi?ID=42 -> SELECT text FROM artikel WHERE ID=42 Problemfall http://webserver/find.cgi?ID=42;UPDATE+USER+SET+TYPE="admin"+WHERE+ID=23 -> SELECT text FROM artikel WHERE ID=42; UPDATE USER SET TYPE="admin" WHERE ID=23 Lösung bei JDBC: Prepared Statement PreparedStatement pstmt = con.prepareStatement("SELECT text FROM artikel WHERE id = ?"); //? Ist Platzhalter für Wert pstmt.setString(1, idParam); //idParam wird automatisch escaped ResultSet rset = pstmt.executeQuery(); //Query ausführen Programmierkurs 34 Hilfestellungen Schritt 1: Interface von Folie 2 nach Eclipse kopieren Schritt 2: Klasse Database als Singleton anlegen public class Database implements IDatabase { private Connection connection; private static Database instance; private Database() {} public static Database getInstance() { if (instance == null) instance = new Database(); return instance; } public void saveUrls(ArrayList<URL> urls) throws Exception { … } … } Programmierkurs 35 Hilfestellungen public void saveEmailAddresses(ArrayList<String> emailAddresses) throws Exception{ //if mysql connection is closed or not established, yet //connect to mysql server //for each email address //create sql statement for inserting email address into table emailaddress //create prepared statement from sql statement //set parameter //execute prepared statement //close prepared statement } Programmierkurs 36 Hilfestellungen public void saveUrls(ArrayList<URL> urls) throws Exception { //if mysql connection is closed or not established, yet //connect to mysql server //for each url //split host of url in parts //find top level domain (tld) //find second level domain (sld) //find upper level domain (uld) //create sql statement for inserting values of tld, sld, uld and visited into table url //build a prepared statement //set parameters in prepared statement //execute the prepared statement //close the prepared statement } Programmierkurs 37 Hilfestellungen public void setUrlVisited(URL url) throws Exception { //if mysql connection is closed or not established, yet //connect to mysql server //split host of url in parts //find top level domain (tld) //find second level domain (sld) //create sql statement for updating table url. Set visited to 1, where tld and sld match. //create prepared statement //set parameters //execute prepared statement //close prepared statement } Programmierkurs 38 Hilfestellungen public URL getRandomUrl() throws Exception { //if mysql connection is closed or not established, yet //connect to mysql server //create sql statement for selecting uld, sld, tld from table url where visited is 0, limit to 1 row //create prepared statement //execute prepared statement //get result set //select next/first result in result set //build URL from result //close result set //close prepared statement //return url } Programmierkurs 39 Hilfestellungen Klasse java.net.URL Neue URL erstellen: URL url = new URL("http://www.google.com"); URL zerlegen in top level domain (tld), sld und uld String[] parts = url.getHost().split("\\."); int length = parts.length; String tld=""; //com if(length > 2) tld = parts[parts.length-1]; String sld=""; //google if(length > 2) sld = parts[parts.length-2]; String uld=""; //www if(length > 2) uld = parts[parts.length-3]; Programmierkurs 40