Entwicklung von Web-Anwendungen mit JAVA EE Grundlagen: Datenbankprogrammierung
Literatur T. Kudraß (Hrsg.): Taschenbuch Datenbanken, Hanser, 2007 DB-Programmierung-2
Einbettungstechniken Einbettung in 3GL Embedded SQL Aufrufschnittstelle Call-Level-Interface (CLI) prozedurale Schnittstelle Sprachen der 4. Generation DB-Programmierung-3
Einbettungsarten statische Einbettung Die DB-Anweisung steht bei der Programmentwicklung fest. dynamische Einbettung Die DB-Anweisung wird zur Laufzeit erst festgelegt. Beispiel: Anfragewerkzeuge, Browser DB-Programmierung-4
Probleme der Einbettung Programmiersprachen kennen keinen Typ "Relation"! Keine mengenorientierten Operationen - Die Verarbeitung von Daten erfolgt satzorientiert! Cursor / Iterator erforderlich Impedance mismatch Programmiersprachen kennen keine NULL-Werte. DB-Programmierung-5
Das Cursor-Konzept Eine Relation wird in der Programmiersprache als Liste behandelt. Ein Cursor ist ein Iterator über eine Liste von Tupeln. Zeiger auf ein Element einer Liste. Cursor können gelesen und weiter gesetzt werden (FETCH NEXT). Implementierungsabhängig gibt es noch weitere Positionierungsoperationen. DB-Programmierung-6
Veranschaulichung: Cursor-Konzept Satzweise Verarbeitung C-Anwendungsprogramm Datenbank Cursor Relation DB-Programmierung-7
Standard SQL - Cursor Deklaration Syntax: <cursor_decl> := DECLARE <cursor_name> [ INSENSITIVE ] [ SCROLL ] CURSOR FOR <cursor_spec> <cursor_spec> := <table_expr> [ ORDER BY { <column_name>//, } ] [ FOR { READ ONLY UPDATE [ OF { <column_name>//, } ] } ] Beispiel: DECLARE c1 CURSOR FOR SELECT Name FROM Angestellte WHERE AbtNr = 'Einkauf' DB-Programmierung-8
Cursor - Zusatz: INSENSITIVE INSENSITIVE Es wird auf einer Kopie der ausgewählten Daten gearbeitet. Änderungen auf den einmal ausgewählten Daten sind für den Cursor unsichtbar. Ohne INSENSITIVE ist es abhängig von der jew. Implementierung, ob Änderungen sichtbar sind, oder nicht. DB-Programmierung-9
Cursor - Zusatz: SCROLL Normalerweise kann nur einmal sequentiell durch die Ergebnismenge gegangen werden. FETCH NEXT SCROLL Erlaubt beliebiges vor- und zurückbewegen: FETCH NEXT FETCH PRIOR FETCH FIRST FETCH LAST FETCH ABSOLUTE n FETCH RELATIVE n DB-Programmierung-10
Cursor - Zusatz: FOR UPDATE Dieser Zusatz ermöglicht das Verändern von Daten beim Iterieren (Positioned Update). Beispiel: DECLARE c1 CURSOR FOR SELECT Name FROM Angestellte WHERE AbtNr = 'Einkauf' FOR UPDATE UPDATE Angestellte SET gehalt = gehalt + 50 WHERE CURRENT OF c1 UPDATE Angestellte SET gehalt = gehalt + 50 WHERE persnr = 4711 DELETE Angestellte WHERE CURRENT OF c1 DB-Programmierung-11
Einbettung in 3 GL (Embedded SQL) Erfordert Vorübersetzer (Precompiler): Programme mit eingebetteten DB-Kommandos werden in übersetzungsfähige Programme transferiert. Die erforderlichen Precompiler werden von den Datenbankherstellern geliefert. Ein Programm enthält also Anweisungen aus zwei verschiedenen Programmiersprachen. Die Einbettung in einige wichtige Sprachen (C, Fortran, Cobol) wurde mit SQL92 genormt. DB-Programmierung-12
Einbettung in 3 GL - Technik Kennzeichnung der DB-Befehle durch das Schlüsselwort: EXEC SQL. Zusätzlich zu den ausführbaren Kommandos kommen deklarative. Spezielle Kommandos: DECLARE, OPEN, FETCH. SQL Statements können sich auf Variablen der Programmiersprache beziehen: host variables Diese werden in der Anfrage durch einen Doppelpunkt gekennzeichnet. DB-Programmierung-13
Einbettung in 3 GL - Übergabe Deklaration von Host-Variablen: EXEC SQL BEGIN DECLARE SECTION; name CHAR(10); abtnr CHAR(10); EXEC SQL END DECLARE SECTION; Binden von Host-Variablen Welche Hostvariablen zur Ein-/Ausgabe von Daten verwendet werden, muss mitgeteilt werden: OPEN: Eingabevariablen FETCH: Ausgabevariablen DB-Programmierung-14
Einbettung in 3 GL - Cursorzugriff Deklaration eines Cursors: EXEC SQL DECLARE cu1 CURSOR FOR SELECT Name FROM Angestellte WHERE AbtNr =?; Öffnen des Cursors: EXEC SQL OPEN cu1 USING :abtnr; Auslesen der Daten: EXEC SQL FETCH cu1 INTO :name; Schließen des Cursors: EXEC SQL CLOSE cu1; DB-Programmierung-15
Dynamische Einbettung in 3 GL Deklaration einer Variablen für die Anfrage: EXEC SQL BEGIN DECLARE SECTION; anfrage_text CHAR(256) varying; pers_nr CHAR(10); EXEC SQL END DECLARE SECTION; Festlegung der Anfrage anfrage_text = "DELETE FROM Angestellte WHERE PersNr =?"; Bekanntmachen der Anfrage EXEC SQL PREPARE anfrage FROM :anfrage_text ; Ausführen der Anfrage EXEC SQL EXECUTE anfrage USING :pers_nr ; DB-Programmierung-16
Einbettung in 3 GL - Schleifensteuerung Reaktion auf spezielle Situationen: EXEC SQL WHENEVER <Bedingung> <Aktion> <Bedingung> := { NOT FOUND SQLWARNING SQLERROR } <Aktion> := { CONTINUE GOTO <label> STOP DO <routine> } DB-Programmierung-17
Einbettung in 3 GL - Beispiel Embedded SQL EXEC SQL BEGIN DECLARE SECTION; name CHAR(50); abtnr INT; EXEC SQL END DECLARE SECTION; EXEC SQL DECLARE cu1 CURSOR FOR SELECT Name FROM Angestellte WHERE abtnr =?; EXEC SQL OPEN cu1 USING :abtnr; for (;;) { EXEC SQL FETCH cu1 INTO :name; EXEC SQL WHENEVER NOT FOUND GOTO FERTIG; printf ("Name des Angestellten: %s", name); } FERTIG: printf ("Alle ausgegeben! \n"); EXEC SQL CLOSE cu1; DB-Programmierung-18
Verarbeitung von Embedded SQL C-Quellcode mit Embedded SQL Precompiler Generierter C-Quellcode C- Compiler DB-Library Linker Compilierter Code Ausführbares Programm DB-Programmierung-19
SQLJ: Embedded SQL für Java // Iteratorklasse definieren #sql iterator It_typ ( String vname, String nname ); It_typ it; // Abfrage durchführen und Iterator dem Ergebnis zuweisen #sql it = { SELECT Vname, NName FROM Angestellte WHERE abtnr = :abtnr }; while (it.next()) { System.out.println ("Name des Angestellten : " + it.vname() + ' ' + it.nname()); } it.close(); System.out.println ("Alle ausgegeben!"); DB-Programmierung-20
Aufrufschnittstellen Es werden Funktionen aus einer Bibliothek verwendet. Die DB-Anfragen werden in der Regel in Textvariablen übergeben. Dynamische Einbettung Beispiele: OCI (Oracle Call Interface) ODBC (Open Database Connectivity) JDBC (Java Database Connectivity) DB-Programmierung-21
Aufrufschnittstellen - jdbc Ausschnitt aus jdbc-programm: String seltext = "SELECT Name FROM Angestellte " + "WHERE AbtNr = 'Einkauf'"; Statement stmt = conn.createstatement(); ResultSet rset = stmt.executequery (seltext); while ( rset.next() ) { System.out.println( "Name des Angestellten: " + rset.getstring("name") ); } System.out.println ("Alle ausgegeben!"); rset.close(); DB-Programmierung-22
jdbc Treiber & Verbindung Es existieren zahlreiche Methoden des Verbindungsaufbaus Einfaches Beispiel: Vor Ausführung des o.a. Programms: import java.sql.*; // Laden der Klasse bewirkt Registrierung Class.forName ("org.gjt.mm.mysql.driver"); // DB-spezifische Verbindungsinfo String cs = "jdbc:mysql:<host>:<port>/<database>"; Connection conn = DriverManager.getConnection(cs+"?user="+un+"&password="+pw); DB-Programmierung-23
jdbc Treiberarchitekturen Typ 1: JDBC-ODBC Bridge plus ODBC driver: Zugriff über ODBC => Es können direkt nur lokale Datenquellen angesprochen werden => nicht plattformunabhängig Typ 2: Native API partly Java driver: JDBC Aufrufe werden in Konstrukte der DB-spezifischen API übersetzt => Auf Client-Seite sind entsprechende API s erforderlich. => nicht plattformunabhängig Typ 3: JDBC Net pure Java driver: Anfragen werden in ein DB-unabhängiges Netzwerkprotokoll übersetzt. Dieses wird vom Server in die entspr. DB-Protokolle übersetzt. Tools des DB-Herstellers erforderlich. Typ 4: Native protocol pure Java driver ("thin client Lösung") Wird direkt in ein Netzwerkprotokoll übersetzt, das von der DB verwendet wird. => direkter Zugriff möglich. => Treiber idr nur vom DB-Hersteller DB-Programmierung-24
JDBC-Treiber Nicht jeder JDBC-Treiber unterstützt alle Features JDBC-Klasse DatabaseMetaData zur Abfrage der unterstützten Funktionen, z.b. supportssavepoints supportsstatementpooling supportsgetgeneratedkeys JDBC-Treiber-Auswahl: http://developers.sun.com/product/jdbc/drivers Auch bedenken: Nicht jeder Server unterstützt alle Features! DB-Programmierung-25
Aufrufschnittstellen - jdbc Ausschnitt aus jdbc-programm: int abtnr = 47; String seltext = "SELECT Name FROM Angestellte " + "WHERE AbtNr = " + abtnr; Statement stmt = conn.createstatement(); ResultSet rset = stmt.executequery( seltext ); while ( rset.next() ) { System.out.println( "Name des Angestellten: " + rset.getstring( "Name" ) ); } System.out.println( "Alle ausgegeben!" ); rset.close(); DB-Programmierung-26
SQL Injection Betrachten Beispiel: String seltext = "SELECT Name FROM Angestellte WHERE pnr=" + vpnr; Alles ok bei: vpnr = "234" Aber was geschieht bei: vpnr = "234A" vpnr = " 'X' OR NOT pnr = 'X' " DB-Programmierung-27
Prepared Statements Ausschnitt aus jdbc-programm: int abtnr = 47; String seltext = "SELECT Name FROM Angestellte " + "WHERE AbtNr =?"; PreparedStatement pstmt = conn.preparestatement( seltext ); pstmt.setint( 1, abtnr ); ResultSet rset = pstmt.executequery(); while ( rset.next() ) { System.out.println( "Name des Angestellten: " + rset.getstring( "Name" ) ); } System.out.println( "Alle ausgegeben!" ); rset.close(); DB-Programmierung-28
Vorteile von Prepared Statements Schutz vor "SQL-Injection" Vorteilhaft für Optimierer Performancevorteile bei mehrfacher Ausführung: Trennung von einmaliger Analyse (prepare) und mehrfacher Ausführung (execute) DB-Programmierung-29
Update Operationen Beispiel: Einfügen neuer Datensätze String stmt = "INSERT INTO Personal(Persnr, Name, Gebdatum) "+ "VALUES (?,?,?)"; PreparedStatement pstmt = conn.preparestatement( stmt ); pstmt.setint( 1, pnr ); pstmt.setstring( 2, name ); pstmt.setdate( 3, gebdat ); int erg = pstmt.executeupdate(); DB-Programmierung-30
Update Operationen 2 Beispiel: Einfügen mehrerer Datensätze String stmt = "INSERT INTO Personal (Persnr, Name) " + "VALUES (?,?)"; PreparedStatement pstmt = conn.preparestatement( stmt ); pstmt.setint( 1, pnr1 ); pstmt.setstring( 2, name1 ); int erg1 = pstmt.executeupdate(); pstmt.setint( 1, pnr2 ); pstmt.setstring( 2, name2 ); int erg2 = pstmt.executeupdate(); DB-Programmierung-31
Batch Updates / Inserts Beispiel: Einfügen mehrerer Datensätze mit einem DB- Aufruf PersonDTO[] personen = ; String stmt = "INSERT INTO Personal (Persnr, Name) " + "VALUES (?,?)"; PreparedStatement pstmt = conn.preparestatement( stmt ); for (PersonDTO p : personen) { pstmt.setint( 1, p.getpersnr() ); pstmt.setstring( 2, p.getname() ); pstmt.addbatch(); } int[] ergs = pstmt.executebatch(); DB-Programmierung-32
Batch Update (2) Batch Update sehr effizient Aber: (Quelle: Javadoc Interface Statement) Submits a batch of commands to the database for execution and if all commands execute successfully, returns an array of update counts.... The elements in the array returned by the method executebatch may be one of the following: A number greater than or equal to zero -- indicates that the command was processed successfully and is an update count giving the number of rows in the database that were affected by the command's execution A value of SUCCESS_NO_INFO -- indicates that the command was processed successfully but that the number of rows affected is unknown If the driver continues processing after a failure, at least one of the elements will be the following: A value of EXECUTE_FAILED -- indicates that the command failed to execute successfully and occurs only if a driver continues to process commands after a command fails If one of the commands in a batch update fails to execute properly, this method throws a BatchUpdateException, and a JDBC driver may or may not continue to process the remaining commands in the batch. However, the driver's behavior must be consistent with a particular DBMS, either always continuing to process commands or never continuing to process commands. DB-Programmierung-33
Kapselung DB-Zugriffe in Klassen kapseln public class ProductDB { public static Collection<ProductDTO> findall(connection cn) { } public static ProductDTO findbyid(connection cn, String id) { } public static int insert (Connection cn, ProductDTO dto){ } public static int update (Connection cn, ProductDTO dto) { } public static int delete (Connection cn, String id) { } } Kommunikation über DTOs Data Transfer Objects Einfache Java Beans zum Datentransport DB-Programmierung-34
Einbettung in 4 GL 4GL - Fourth Generation Language Datenbanksprache Programmiersprache mit integriertem Datenbanktypkonzept Beispiele: Natural (Software AG) ABAP (SAP AG) Gupta SQL PowerBuilder (Sybase) PL/SQL (Oracle)... DB-Programmierung-35
Einbettung in 4 GL Merkmale: Einheitliche Sprache zur Bearbeitung von Daten im Programm und in der Datenbank. Mengenorientierte Verarbeitung möglich. IdR Tabellen als Programmiersprachentyp. Oft: Integrierte Möglichkeiten zur grafischen Darstellung. DB-Programmierung-36
Einbettung in 4 GL - Beispiel Programmbeispiel ABAP: Data name TYPE Angestellte-Name. SELECT Name FROM Angestellte INTO name WHERE AbtNr = 'Einkauf'. WRITE: / 'Name des Angestellten: ', name. ENDSELECT. WRITE: / 'Alle ausgegeben! '. DB-Programmierung-37
Einbettung in 4 GL - Beispiel2 ABAP mit internen Tabellen: Data name TYPE Angestellte-Name. Data ntab TYPE TABLE OF Angestellte-Name. SELECT Name FROM Angestellte INTO TABLE ntab WHERE AbtNr = 'Einkauf'. LOOP AT ntab INTO name. WRITE: / 'Name des Angestellten: ', name. ENDLOOP. WRITE: / 'Alle ausgegeben! '. DB-Programmierung-38
Einbettung in 4 GL - Beispiel 3 Analoge Operationen sind auf Programm- und Datenbanktabellen möglich: Data name TYPE Angestellte-Name. Data angtab TYPE TABLE OF Angestellte. SELECT * FROM Angestellte INTO TABLE angtab. LOOP AT angtab WHERE AbtNr = 'Einkauf' INTO name. WRITE: / 'Name des Angestellten: ', name. ENDLOOP. WRITE: / 'Alle ausgegeben! '. DB-Programmierung-39