Programmieren II. Dr. Klaus Höppner. Hochschule Darmstadt Sommersemester / 39

Ähnliche Dokumente
Programmieren II. Objekt-relationales Mapping. Vorlesung 08. Handout S. 1. Martin Schultheiß. Hochschule Darmstadt Sommersemester 2011

Programmieren II. Objekt-relationales Mapping. Vorlesung 12. Handout S. 1. Dr. Klaus Höppner. Hochschule Darmstadt Sommersemester 2009

Workshop Java Webentwicklung Einführung in Hibernate. Ulrich Stärk

Programmieren II. Objekt-relationales Mapping. Hibernate. Hibernate. Dr. Klaus Höppner. Hochschule Darmstadt SS 2008

Persistenz von Objekten relationale Datenbank Eigene Datenstruktur XML (JAXB) Proprietäre Dateiformate (Lochkarten)

Übungsaufgabe Transaktion als Middleware

Eclipse und EclipseLink

4. Objektrelationales Mapping Grundlagen der Programmierung II (Java)

Gregor Raschke 2008 HIBERNATE. Eine Einführung

Hibernate. Vortragender : Nabil Janah Kursleiter : Prof. Dr. Björn Dreher Lehrveranstaltung : Komponenten-Architekturen. Nabil janah 1 Hibernate

Analyse und praktischer Vergleich von neuen Access- Layer-Technologien in modernen Webanwendungen unter Java. Oliver Kalz

Programmieren II. Beispiele für RDBMS. Relationale Datenbanken. Datenbanken SQL. Dr. Klaus Höppner JDBC. Hochschule Darmstadt SS 2008

Oracle: Abstrakte Datentypen:

Java Forum Stuttgart 2013 twitter.com/kspichale spichale.blogspot.de

Softwareentwicklung mit Enterprise JAVA Beans

ibatis SQL Maps Einführung

JDBC. Es kann z.b. eine ODBC-Treiberverbindung eingerichtet werden, damit das JAVA-Programm auf eine ACCESS-DB zugreifen kann.


Referent: Marko Modsching. Vortrag: JPA mit Hibernate. Datum: Deutsche Software Engineering & Research GmbH

Grundlagen von Datenbanken SS 2010 Kapitel 8: Datenbank-Einbettung in Programmiersprachen Prof. Dr. Stefan Böttcher Universität Paderborn

3. Datenbankzugriff (JDBC) Grundlagen der Programmierung II (Java)

Einführung in die Informatik II

»Java-Persistenz mit Hibernate«Technology Days Workshop

Hochschule Karlsruhe Technik und Wirtschaft Anhänge: Fakultät für Informatik und Wirtschaftsinformatik SS 2013 Prof. Schmidt.

Datenbankentwurf & Datenbankzugriff mit JDBC. Georg Köster Sven Wagner-Boysen

Client/Server-Programmierung

DATENBANKEN SQL UND SQLITE VON MELANIE SCHLIEBENER

Object Relational Mapping Layer

Beispiel: DB-Mock (1/7)

JdbcTemplate

Java und Datenbanksysteme Datenbankanbindung mit JDBC

Open-Source Transparente Persistence (keine Interfaces, keine Ober- Klassen) Caching

Java Persistence API 2.x. crud + relationships + jp-ql

seit Java 1.1 Bestandteil der API: packages java.sql, javax.sql

Java Database Connectivity (JDBC) Walther Rathenau Gewerbeschule 1

Informationsintegration und Web-Portale. Tutorial: Enterprise Java Beans. Erik Buchmann

Datenbanken & Informationssysteme Übungen Teil 1

Algorithmen und Datenstrukturen II

Programmieren II. Relationale Datenbanken. Vorlesung 07. Handout S. 1. Martin Schultheiß. Hochschule Darmstadt Sommersemester 2011.

Java und Datenbanken Ein Überblick

Views in SQL. 2 Anlegen und Verwenden von Views 2

SQL structured query language

Java Database Connectivity-API (JDBC)

Modifikation der Datenbank

UNIVERSITÄT ULM Fakultät für Ingenieurswissenschaften und Informatik Institut für Datenbanken und Informationssysteme

Analyse und Modellierung von Informationssystemen

ORM & OLAP. Object-oriented Enterprise Application Programming Model for In-Memory Databases. Sebastian Oergel

Einführung in JDBC. IFIS Universität zu Lübeck

Datenbanksysteme I Datenbankprogrammierung Felix Naumann

Nathan Burgener. Design by Contract. Modul SWE

DB-Programmierung. Lehr- und Forschungseinheit Datenbanken und Informationssysteme 1. Ziele. DB2 Zugriff mit Java selbst programmieren

Hibernate Search. Unterstützung laufender Java Projekte. Perfect Match Rent-a-team Coaching on the project Inhouse Outsourcing

Benutzung eines Login Modules zur Authentifizierung unter JBoss 4.0.5

Webbasierte Informationssysteme

Java Persistenz mit JPA und Hibernate. Michael Plöd - Senacor Technologies AG

SQL für Trolle. mag.e. Dienstag, Qt-Seminar

Programmieren I. Strategie zum Entwurf von Klassen. Beispiele. Design von Klassen. Dr. Klaus Höppner. Beispiel: Bibliothek

Inhalt. Ein Einführung in die Nutzung von SQL-Datenbanken am Beispiel Oracle. Daten und Tabellen - ein Beispiel. Daten und Tabellen - Normalisierung

Dipl. Inf. Dipl. Math. Y. Orkunoglu Datum:

Kapitel 8: Datenbankanbindung. SoPra 2008 Kap. 8: Datenbankanbindung (1/40)

Labor 3 - Datenbank mit MySQL

Datenbanken Objektrelationales Mapping Spezifikation

Übung 1 mit C# 6.0 MATTHIAS RONCORONI

Datenmanagement in Android-Apps. 16. Mai 2013

SQL Tutorial. SQL - Tutorial SS 06. Hubert Baumgartner. INSO - Industrial Software

Datenbanken SQL Einführung Datenbank in MySQL einrichten mit PhpMyAdmin

Klausur zur Vorlesung Datenbanksysteme I

MySQL-Befehle. In diesem Tutorial möchte ich eine kurze Übersicht der wichtigsten Befehle von MySQL geben.

JDBC. Allgemeines ODBC. java.sql. Beispiele

Java Application 1 Java Application 2. JDBC DriverManager. JDBC-ODBC Br idge. ODBC Driver Manager. Dr iver C. Dr iver D.

Datenbank und Informationssysteme

Strukturierte Objekttypen

Analyse und Modellierung von Informationssystemen

Datenbank Anbindung. Arthur Zaczek. Nov 2014

Kein blasses Schema? NoSQL und Big Data mit Hibernate OGM

Analyse und Modellierung von Informationssystemen

Datenbanksysteme I. Klausur zum Praktikum. Mehrere Professoren prüfen mit genau einem Beisitzer genau einen Studenten.

Programmieren in Java

LINQ. LANGUAGE INTEGREATED QUERY.net 3.5. Bernhard Grojer

Kapitel 33. Der xml-datentyp. In diesem Kapitel: Der xml-datentyp 996 Abfragen aus xml-datentypen 1001 XML-Indizierung 1017 Zusammenfassung 1023

Algorithmen und Datenstrukturen

Wie kommen die Befehle zum DBMS

Bean-Mapping mit MapStruct

FileMaker und Java...und es öffnen sich neue Welten!

Einstieg in die Informatik mit Java

Javakurs 2013 Objektorientierung

Chancen und Wachstumsfelder für PostgreSQL

Datenbankzugriff mit JDBC

Referenzielle Integrität SQL

SQL Tutorium Documentation

Benutzung eines Login Modules zur Authentifizierung unter JBoss 4.2.x

Angewandte Softwareentwicklung Serialisierung

Hilfe meine Oracle Datenbank spricht nicht mit meiner JSP

Repetitorium Informatik (Java)

Objektrelationale und erweiterbare Datenbanksysteme

SQL: statische Integrität

Objekt-relationales Mapping und Performance-Tuning

Betreutes Programmieren Vorlesung Informatik II, Blatt 7 Musterlösung

Transkript:

Programmieren II Dr. Klaus Höppner Hochschule Darmstadt Sommersemester 2010 1 / 39

Objekt-relationales Mapping 2 / 39

Objekt-relationales Mapping Mit JDBC kann Java sich mit relationalen Datenbanken verbinden. Hierbei entsprechen jeder Datensatz einer Zeile in einer Datenbanktabelle und die Attribute eines Datensatzes den Tabellenspalten. Daher ist es prinzipiell möglich, eine Abbildung zwischen den Datensätzen in einer Tabelle und klassischen Java-Objekten (POJO plain old Java objects) herzustellen. Eine solche Abbildung nennt man objekt-relationales Mapping (ORM). 3 / 39

Beispieltabelle: Customer Die folgende Tabelle beschreibt einen Kunden mit Adresse, wobei die ID des Kunden automatisch generiert wird (entsprechend des SQL-Dialektes für HSQLDB): CREATE TABLE CUSTOMER( ID INTEGER GENERATED BY DEFAULT AS IDENTITY(START WITH 0) NOT NULL PRIMARY KEY, FIRSTNAME VARCHAR(20), LASTNAME VARCHAR(20), STREET VARCHAR(20), CITY VARCHAR(20) ) 4 / 39

Korrespondierende Klasse Customer public class Customer { private Integer id; private String firstname; private String lastname; private String street; private String city; public Integer getid() { return id; public void setid(integer id) { this.id = id; 5 / 39

Korrespondierende Klasse Customer (Forts.) public String getfirstname() { return firstname; public void setfirstname(string firstname) { this.firstname = firstname; // Weitere Getter und Setter analog @Override public String tostring() { return String.format( "%s %s, %s, %s", firstname, lastname, street, city); 6 / 39

Klasse DBConnection Das Laden des JDBC-Treibers und der Aufbau der Verbindung wird in eine eigene Klasse ausgelagert: public class DBManager { private Connection conn; public DBManager() { try { Class.forName("org.hsqldb.jdbcDriver"); conn = DriverManager.getConnection( "jdbc:hsqldb:file:data/fibu;shutdown=true", "SA",""); catch (Exception e) { e.printstacktrace(); 7 / 39

Klasse DBConnection (Forts.) public void close() { if (conn!=null) { try { conn.close(); catch (SQLException e) { e.printstacktrace(); finally { conn = null; 8 / 39

Verknüpfung DB-Tabelle Java-Objekt Nun sollen Java-Objekte persistent gemacht werden, indem Objekte vom Typ Customer mit der gleichnamigen DB-Tabelle synchronisiert werden können. Hierzu werden der Klasse DBManager zwei neue Methoden hinzugefügt: Customer load(integer id) Hier werden für eine ID die Werte der Attribute per SELECT aus der Tabelle geholt und eine neue Instanz von Customer erzeugt. void persist(customer c) Hier werden die Werte der Attribute von c in die Tabelle geschrieben, wobei bei leerer ID (null) ein neuer Datensatz per INSERT eingefügt, andernfalls die Feldwerte des existierenden Datensatzes per UPDATE aktualisiert werden. 9 / 39

Methode load von DBManager public Customer load(integer id) { Customer c = null; try { PreparedStatement st = conn.preparestatement( "select * from CUSTOMER where id=?"); st.setint(1, id); ResultSet res = st.executequery(); if (res.next()) { c = new Customer(); c.setid(res.getint("id")); c.setfirstname(res.getstring("firstname")); c.setlastname(res.getstring("lastname")); c.setstreet(res.getstring("street")); c.setcity(res.getstring("city")); res.close(); catch (SQLException e) { e.printstacktrace(); return c; 10 / 39

Methode persist von DBManager public void persist(customer c) { PreparedStatement st; try { if (c.getid()==null) { st = conn.preparestatement("insert into CUSTOMER"+ "(FIRSTNAME,LASTNAME,STREET,CITY) values (?,?,?,?)"); else { st = conn.preparestatement("update CUSTOMER set"+ "FIRSTNAME=?, LASTNAME=?, STREET=?, CITY=? where id=?"); st.setint(5, c.getid()); st.setstring(1, c.getfirstname()); st.setstring(2, c.getlastname()); st.setstring(3, c.getstreet()); st.setstring(4, c.getcity()); st.executeupdate(); 11 / 39

Methode persist von DBManager (Forts.) if (c.getid()==null) { st = conn.preparestatement("call identity()"); ResultSet res = st.executequery(); res.next(); c.setid(new Integer(res.getInt(1))); res.close(); catch (SQLException e) { e.printstacktrace(); 12 / 39

Exkurs: PreparedStatement In der Realisierung von fetch() und update() wurde statt Statement jeweils PreparedStatement benutzt. Bei PreparedStatement wird beim Anlegen das Statement bereits mit einem SQL-Befehl (i. A. mit Platzhaltern) vorbereitet. Dieser wird von der Datenbank vorkompiliert. Danach können die Platzhalter mit den realen Werte belegt werden. Vorteile: Bei mehrfacher Verwendung (z. B. in Schleifen) ergibt sich ein Laufzeitgewinn, da der Befehl schon vorkompiliert ist. Da die Gültigkeit der Parameter überprüft wird und SQL-Sonderzeichen (z. B. ) geschützt werden, werden so genannte SQL-Injections verhindert. 13 / 39

Kleiner Cartoon Quelle: http://xkcd.com/327/ 14 / 39

Zusammenfassung In diesem Abschnitt wurde anhand einer einfachen Tabelle demonstriert, wie ein objekt-relationales Mapping selber realisiert werden kann. Der Aufwand war aber recht hoch, da individuell für die Klasse die entsprechenden Methoden zur Synchronisation inkl. der entsprechenden SQL-Befehle implementiert wurden. Wegen verschiedener SQL-Dialekte der RDBMS ist die Implementierung auch DB-spezifisch. Der Aufwand wird noch höher, wenn Tabellen über Schlüssel miteinander verknüpft sind. Daher werden in der Praxis für ORM spezielle Frameworks benutzt. 15 / 39

Hibernate Es existieren verschiedene Frameworks, die ein objekt-relationales Mapping realisieren, mittlerweile standadisiert über die Java Persistence API JPA. Eines der bekanntesten und häufig benutzten ist Hibernate (http://www.hibernate.org). Was ist der Vorteil eines solchen Frameworks und ORM? Es verbindet die Vorteile der objektorientierten Programmierung mit den Vorteilen einer Datenbank, insbesondere der Persistenz (d. h. dass Datensätze in einem RDBMS nicht flüchtig sind). So kann man persistente Objekte realisieren, die sich weitgehend wie normale Java-Objekte verwenden lassen. 16 / 39

Geschichte Hibernate wurde von der Firma JBoss entwickelt, die sich mit Open-Source-Software im Bereich Java-Middleware, -Applikationsservern und Message-Brokern beschäftigt. Mittlerweile wurde JBoss (nach einem Bieterkampf mit Oracle) von RedHat übernommen. 17 / 39

Architektur Hibernate stellt in der einfachsten Benutzungsform dem Anwender eine Datenbank-Session zur Verfügung, die nach Konfiguration eines Datenbanktyps und der Datenbankparameter geöffnet wird. Objekte können sich in drei Zuständen befinden: transient Das Objekt ist noch nicht mit der Datenbank verknüpft, also flüchtig. persistent Das Objekt ist im aktuellen Kontext mit der Datenbank verknüpft. detached Das Objekt war mit der Datenbank verknüpft, der Kontext existiert aber nicht mehr. Daher ist das Objekt aktuell losgelöst. 18 / 39

Schaubild 19 / 39

Konfiguration einer Hibernate-Anwendung In der Java-SE verwendet man i. A. mit Hibernate einen Entity-Manager, der aus einer so genannten Persistence Unit erzeugt wird. Hierbei erfolgt die Konfiguration der Persistence Unit in der Datei META-INF/persistence.xml: <?xml version="1.0" encoding="utf-8"?> <persistence xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/xmlschema-instance" xsi:schemalocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence version="2.0"> <persistence-unit name="manager1" transaction-type="resource_local"> <properties> <property name="javax.persistence.jdbc.driver" value="org.hsqldb.jdbcdriver"/> <property name="javax.persistence.jdbc.user" value="sa"/> <property name="javax.persistence.jdbc.password" value=""/> <property name="javax.persistence.jdbc.url" value="jdbc:hsqldb:file:data/fibu;shutdown=true"/ <property name="hibernate.dialect" value="org.hibernate.dialect.hsqldialect"/> <property name="hibernate.max_fetch_depth" value="3"/> </properties> </persistence-unit> </persistence> 20 / 39

Anlegen des Entity-Managers import javax.persistence.*; public class Anwendung { public static void main(string[] args) { EntityManagerFactory emf = Persistence.createEntityManagerFactory("manager1"); EntityManager em = emf.createentitymanager(); // Arbeiten mit persistenten Objekten em.close(); emf.close(); 21 / 39

Grundlagen von ORM Durch ORM werden Klassen mit Tabellen und Instanzen der Klassen mit Datensätzen innerhalb der Tabelle verknüpft. Damit Instanzen eindeutig Datensätzen zugeordnet werden können, muss die Datenbanktabelle einen eindeutigen Primärschlüssel besitzen. Dieser wird dann als WHERE-Ausdruck in den abgesetzten SQL-Anweisungen verwendet. Weiterhin dient die Existenz einer Primär-ID im Objekt der Unterscheidung, ob ein nicht persistentes Objekt transient oder detached ist. 22 / 39

Faustregeln Im Allgemeinen wird eine Tabelle der Datenbank einer Java-Klasse zugeordnet. Diese Klasse muss einen Standardkonstruktor besitzen. Die Attribute der Tabelle werden auf entsprechende Attribute der Klasse abgebildet. In der Klasse werden dann Getter und Setter für diese Attribute definiert. Die eigentliche Zuordnung zwischen Klasse und Tabelle erfolgt dann über eine XML-Datei, die insbesondere den Primärschlüssel angibt, der zur Identifikation von Elementen verwendet wird, sowie die Namen von Tabellenspalten den Attributen der Klasse zuordnet. 23 / 39

Beispiel: Datenbank Fibu Hier nun ein Datenbankschema für eine Buchhaltung: Invoice ID : INTEGER CUSTOMERID : INTEGER TOTAL : DECIMAL(10,2) Customer ID : INTEGER FIRSTNAME : VARCHAR(20) LASTNAME : VARCHAR(20) Item ITEM : INTEGER INVOICEID : INTEGER PRODUCTID : INTEGER QUANTITY : INTEGER COST : DECIMAL(10,2) PRODUCT ID : INTEGER NAME : VARCHAR(20) PRICE : DECIMAL(10,2) 24 / 39

Erster Ansatz: Klasse Invoice import javax.persistence.*; @Entity public class Invoice { private Integer id; private Integer customerid; private Double total; @Id @GeneratedValue(strategy=GenerationType.AUTO) public Integer getid() { return id; public void setid(integer id) { this.id = id; 25 / 39

Erster Ansatz: Klasse Invoice (Forts.) public Integer getcustomerid() { return customerid; public void setcustomerid(integer customerid) { this.customerid = customerid; public Double gettotal() { return total; public void settotal(double total) { this.total = total; 26 / 39

Mapping Während in Hibernate das ORM ursprünglich über XML-Dateien erfolgte, geht dies nun über Annotationen: Die Klasse Invoice wird über Annotation als Entität gekennzeichnet, wobei per Default angenommen wird, dass die Datenbanktabelle den selben Namen hat. Dann wird das Attribut id der Java-Klasse als Primärschlüssel markiert. Alle weiteren Attribute der Klasse werden automatisch auf die Datenbankspalte gleichen Namens abgebildet. 27 / 39

Zweiter Ansatz für Invoice In Wirklichkeit möchte man in der Klasse Invoice statt der reinen Kundennr. lieber direkt eine Referenz auf den Kunden haben: @Entity public class Invoice {... private Customer customer;... @ManyToOne @JoinColumn(name="CUSTOMERID") public Customer getcustomer() { return customer; public void setcustomer(customer customer) { this.customer = customer; 28 / 39

Mapping Dies ist ein Fall einer Zuordnung many-to-one: Mehrere Rechnungen können für denselben Kunden ausgestellt sein. Diese Abbildung erfolgt über die Annotation @ManyToOne, wobei der Name der Tabellenspalte mit dem Fremdschlüssel angegeben werden muss, wenn diese Spalte nicht einfach FKTAB_ID heißt, wobei FKTAB der Name der verknüpften Tabelle ist. Die Klasse Customer muss natürlich auch entsprechend mit Annotationen für JPA versehen sein. 29 / 39

Mapping der Rechnungspositionen Einer Rechnung sind in der Regel viele Rechnungsposten zugeordnet. Die Zuordnung erfolgt durch die Spalte invoiceid in der Tabelle Item. Hierfür wird in der Klasse Invoice nun eine Collection von Item neu hinzugefügt, die eine Abbildung vom Typ one-to-many ist. Hierbei wird für die Zuordnung die Spalte invoiceid aus Item als foreign key verwendet, anhand dessen die passenden Rechnungsposten ausgewählt werden. Zusätzlich wird direkt die Tabelle Product anhand der Produktnr. des Rechnungsposten in die Klasse Item abgebildet. 30 / 39

Klasse Invoice @Entity public class Invoice { private Collection<Item> items; @OneToMany(mappedBy="invoice") public Collection<Item> getitems() { return items; public void setitems(collection<item> items) { this.items = items; 31 / 39

Klasse Item @Entity public class Item { private Integer id; private Invoice invoice; private Product product; private Integer quantity; @Id @Column(name="ITEM") @GeneratedValue(strategy=GenerationType.AUTO) public Integer getid() { return id; public void setid(integer id) { this.id = id; 32 / 39

Klasse Item (Forts.) @ManyToOne @JoinColumn(name="INVOICEID") public Invoice getinvoice() { return invoice; public void setinvoice(invoice invoice) { this.invoice = invoice; @ManyToOne @JoinColumn(name="PRODUCTID") public Product getproduct() { return product; public void setproduct(product product) { this.product = product; 33 / 39

Klasse Item (Forts.) public Integer getquantity() { return quantity; public void setquantity(integer quantity) { this.quantity = quantity; 34 / 39

Klasse Product @Entity public class Product { private Integer id; private String name; private Double price; @Id public Integer getid() { return id; public void setid(integer id) { this.id = id; 35 / 39

Klasse Product (Forts.) public String getname() { return name; public void setname(string name) { this.name = name; public Double getprice() { return price; public void setprice(double price) { this.price = price; 36 / 39

Anwendung public class Anwendung { public static void main(string[] args) { EntityManagerFactory emf = Persistence.createEntityManagerFactory("manager1"); EntityManager em = emf.createentitymanager(); EntityTransaction tx = em.gettransaction(); tx.begin(); Customer c = em.find(customer.class, new Integer(5)); System.out.println(c); c.setcity("frankfurt"); tx.commit(); 37 / 39

Anwendung (Forts.) tx.begin(); c = new Customer(); c.setfirstname("karl"); c.setlastname("meier"); c.setstreet("ahornweg"); c.setcity("köln"); em.persist(c); tx.commit(); System.out.println(c.getId()); 38 / 39

Anwendung (Forts.) Invoice inv = em.find(invoice.class, new Integer(2)); System.out.println(inv.getCustomer()); for (Item item : inv.getitems()) { System.out.format("%d mal %s\n", item.getquantity(), item.getproduct().getname()); em.close(); emf.close(); 39 / 39