Fakultät für Informatik & Wirtschaftsinformatik DB & IS II - WS 2016 Object Relational Mapping Layer Views Controlers Business logic GUI OO-application logic Object-relational-Mapping Relational DBMS Andreas Schmidt PHP (Teil 3) 1/33 Fakultät für Informatik & Wirtschaftsinformatik DB & IS II - WS 2016 object relational mapping layer • two concepts: • descriptive query language SQL (set oriented) • imperative programming language (tuple oriented) • solution: build a mapping layer between the database and the application layer • which functionality should the mapping layer provides ? • mapping of PHP objects and their relations to database tables • encapsulation of SQL statements • decoupling of the application logic from the database design • which functionality should the mapping layer not provides ? • application logic Andreas Schmidt PHP (Teil 3) 2/33 Fakultät für Informatik & Wirtschaftsinformatik DB & IS II - WS 2016 object relational mapping layer • observation: a number of operations can be derived out of the ER-Diagram (or UML-Diagram): • creation/deletion of objects • modification of objects • modification of relations between objects • search for objects • this functionality is also known as CRUD-funktionality (Create, Read, Update, Delete) Andreas Schmidt PHP (Teil 3) 3/33 Fakultät für Informatik & Wirtschaftsinformatik DB & IS II - WS 2016 CRUD Interface - necessary methods plays_role id <0,n> id <0,n> Person Film <0,1> title Andreas Schmidt year birthday <0,n> directs firstname surname PHP (Teil 3) 4/33 Fakultät für Informatik & Wirtschaftsinformatik DB & IS II - WS 2016 Tabellenstruktur CREATE TABLE person ( id INT (10) AUTO_INCREMENT, name VARCHAR (40) NOT NULL, vorname VARCHAR(40) NOT NULL, geburtsjahr YEAR(4), PRIMARY KEY(id) ) TYPE=InnoDB; CREATE TABLE film ( id INT (10) AUTO_INCREMENT, titel VARCHAR (100) NOT NULL, jahr year(4), regisseur_fk INT (10), FOREIGN KEY (regisseur_fk) REFERENCES person(id) ON DELETE SET NULL, PRIMARY KEY(id) ) TYPE=InnoDB; CREATE TABLE hat_rolle ( schauspieler_fk INT(10) NOT NULL, film_fk INT(10) not null, FOREIGN KEY(film_fk) REFERENCES film(id) ON DELETE CASCADE, FOREIGN KEY(schauspieler_fk) REFERENCES person(id) ON DELETE CASCADE ) TYPE=InnoDB; Andreas Schmidt PHP (Teil 3) 5/33 Fakultät für Informatik & Wirtschaftsinformatik DB & IS II - WS 2016 Klassenstruktur in PHP (Variante 1) class CRUD_Film { private private private private private class CRUD_Person { $id; $title; $year; $regisseur; $actors = array(); private private private private private private function __construct(...) { function __construct(...) { } } // ... // ... } Andreas Schmidt $id; $firstname; $surname; $birthdate; $directed_films = array(); $films = array(); } PHP (Teil 3) 6/33 Fakultät für Informatik & Wirtschaftsinformatik DB & IS II - WS 2016 Klassenstruktur in PHP (Variante 2) class CRUD_Film { private private private private class CRUD_Person { $id; $title; $year; $regisseur_fk; private private private private function __construct(...) { function __construct(...) { } } // ... // ... } Andreas Schmidt $id; $firstname; $surname; $birthdate; } PHP (Teil 3) 7/33 Fakultät für Informatik & Wirtschaftsinformatik DB & IS II - WS 2016 CRUD Interface - necessary methods (Class CRUD_Person) • static methods: • instance methods: $p->delete() $p = CRUD_Person::create($name, ...) $p = CRUD_Person::get($id) $p_list = CRUD_Person::query($cond) // Accessor/Mutatormethoden: $p->getFirstname(), $f->setFirstname($n) $p->getSurname(), $p->setSurname($n) $p->getBirthday(), $p->setBirthday($d) $p->getFilms() $p->getDirectedFilms() // Modification of Relationships $p->addFilm($film) $p->deleteFilm($film) $p->addDirectedFilm($film) $p->delDirectedFilm($film) Andreas Schmidt PHP (Teil 3) 8/33 Fakultät für Informatik & Wirtschaftsinformatik DB & IS II - WS 2016 CRUD Interface - necessary methods (Class CRUD_Film) • static methods: • instance methods: $f->delete() $f = CRUD_Film::create($title, $year) $f = CRUD_Film::get($id) // Accessor/Mutatormethoden: f->getTitle(), $f->setTitle($t) $f->getYear(), $f->setYear($y) $f_list = CRUD_Film::query($cond) $f->getRegisseur() $f->getActors() // Modification of Relationships $f->addActor($actor) $f->deleteActor($actor) $f->setRegisseur($r) $f->unsetRegisseur() Andreas Schmidt PHP (Teil 3) 9/33 Fakultät für Informatik & Wirtschaftsinformatik DB & IS II - WS 2016 CRUD interface (1) relation between methods and SQL-statements method SQL-statement Parameter CRUD_Film::create($title, $year) INSERT VALUES INSERT VALUES $title, $year CRUD_Film::get($id) SELECT id, title, year, regisseur_fk FROM Film WHERE id = ? $id CRUD_Film::query($cond) SELECT id, title, year, regisseur_fk FROM Film WHERE $cond $cond $f->delete() DELETE FROM Film WHERE id = ? $this->id $f->setTitle($title) UPDATE Film SET title = ? WHERE ID = ? $title $this->id Andreas Schmidt INTO Film (title, year) -- mysql (?, ?) INTO Film (title, year, id) -- oracle (?, ?, seq.nextval) PHP (Teil 3) 10/33 Fakultät für Informatik & Wirtschaftsinformatik DB & IS II - WS 2016 CRUD interface (2) method SQL-statement SQL-parameter $f->addActor($actor) INSERT INTO plays_role (actor_fk, film_fk) VALUES (? , ?) $actor->getId(), $this->id $f->deleteActor($actor) DELETE from plays_role WHERE actor_fk = ? AND film_fk = ? $actor->getId(), $this->id $f->getActors() SELECT FROM WHERE AND $this->id $f->setRegisseur($person) UPDATE Film SET regisseur_fk = ? WHERE ID = ? $person->getId(), $this->id $f->getRegisseur() SELECT surname, prename, id, birthday FROM Person WHERE id = ? $this->regisseur_fk Andreas Schmidt prename, surname, id, birthday Person, plays_role plays_role.film_fk = ? plays_role.actor_fk=Person.id PHP (Teil 3) 11/33 Fakultät für Informatik & Wirtschaftsinformatik DB & IS II - WS 2016 example implementation (getActors()) class CRUD_Film { // other methods in this class ... function getActors() { $db = PDO_Util::getConnection(); $sql = "SELECT id, prename, surname, birthday FROM Person, plays_role WHERE plays_role.actor_fk=Person.id AND plays_role.film_fk = ?"; $stmt = $db->prepare( $sql ); $stmt->execute(array($this->id)); $list = array(); while($row = $stmt->fetch()) $list[] = new CRUD_Person($row[0], $row[1], $row[2], $row[3]); return $list; } } // end class Film Andreas Schmidt PHP (Teil 3) 12/33 Fakultät für Informatik & Wirtschaftsinformatik DB & IS II - WS 2016 First Level Cache • Werden Änderungen an den Objekten nicht sofort in die Datenbank geschrieben kann es sein, dass mehrere Kopien desselben Objektes im Speicher existieren, die einen unterschiedlichen Status haben • Ausweg: Cache • Prinzip: • jedes Objekt, das aus Datenbank gelesen wird, wird in Cache eingetragen • beim Zugriff auf DB wird geschaut ob sich Objekt nicht bereits in Cache befindet, wenn ja dann wird das Objekt zurückgeliefert (zusätzlich Performancegewinn !!) • bei Commit werden die geänderten Objekte des Caches zurückgeschrieben • Implementierung: • z.B. mit assoziativem Array (Dictionary), wobei der Schlüssel durch Objekt-ID repräsentiert wird und der Wert durch das Objekt selbst (Reference auf Objekt) Andreas Schmidt PHP (Teil 3) 13/33 Fakultät für Informatik & Wirtschaftsinformatik DB & IS II - WS 2016 First Level Cache $obj1 $stadt3 $hauptstadt Cache Andreas Schmidt PHP (Teil 3) 14/33 Fakultät für Informatik & Wirtschaftsinformatik DB & IS II - WS 2016 Second level cache • Bereits angefrage Datensätze verbleiben im Cache und werden bei späteren Anfragen von dort geladen • Geeignet für folgende Typen von Daten: • geringe Änderungsrate • unkritische Daten (non financial) • Anwendungslokale (non shared) Daten • Reference data • geringe Anzahl von Instanzen • jede Instanz ist mit vielen Instanzen anderer Klassen verbunden • seltener Update Andreas Schmidt PHP (Teil 3) 15/33 Fakultät für Informatik & Wirtschaftsinformatik DB & IS II - WS 2016 Synchronisation • Szenario: • User 1 liest Datensatz und modifiziert ihn in einer Bildschirmmaske • User 2 liest anschließend denselben Datensatz und modifiziert ihn ebenfalls • • User 1 speichert den geänderten Datensatz zurück User 2 speichert ebenfalls den von ihm geänderten Datensatz zurück • Problem: • Änderungen von User 1 sind verloren gegangen Andreas Schmidt PHP (Teil 3) 16/33 Fakultät für Informatik & Wirtschaftsinformatik DB & IS II - WS 2016 Lösungsansätze • Pessimistische Synchronistaion • zu bearbeitender Datensatz wird während der Dauer der Bearbeitung gesperrt (Sperrattribut, Tabelle(n) zur Sperrenverwaltung) • Optimistische Synchronisation • man geht von keiner „Kollision“ aus • tritt Kollision auf, so muss diese von der Anwendung/dem Anwender gelöst werden • Prinzip: • Datensatz erhält zusätzliches Attribut mit Zeitstempel oder Versionsnummer • Bei jeder Modifikation wird Zeitstempel neu gesetzt, bzw. Versionsnummer hochgezählt • Beim Abspeichern wird der aktuelle Wert des Zeitstempels bzw. der Versionsnummer mit verglichen Andreas Schmidt PHP (Teil 3) 17/33 Fakultät für Informatik & Wirtschaftsinformatik DB & IS II - WS 2016 DDL (optimistische Synchronisation) create table Person ( id integer primary key, name varchar(40) not null, vorname varchar(40) not null, geburtsdatum date, version integer not null ); Andreas Schmidt PHP (Teil 3) 18/33 Fakultät für Informatik & Wirtschaftsinformatik DB & IS II - WS 2016 Beispiel bei Update versionsnummer hochzählen function update() { $db = PDO_Util::getConnection(); $sql = "update person set name=?, vorname=?, version=version+1 where id=? and version= ?"; $values = array($this->name, $this->vorname, $this->id, $this->version); $stmt = $db->prepare( $sql ); $stmt->execute( $values ); $affected_rows = $stmt->rowCount(); if ($affected_rows != 1) return false; else { $this->version++; return true; } test ob Datensatz zurückgeschrieben wurde } update des Zählers in der Instanz Andreas Schmidt PHP (Teil 3) 19/33 Fakultät für Informatik & Wirtschaftsinformatik DB & IS II - WS 2016 Vererbung vorname Person name eintrittsdatum isa Angestellte Kunde bonusmeilen sicherheitsstufe Andreas Schmidt Bodenpersonal isa flugstunden Pilot PHP (Teil 3) 20/33 Fakultät für Informatik & Wirtschaftsinformatik DB & IS II - WS 2016 relationale Modellierung • 1 Tabelle pro Klassenhierarchie • 1 Tabelle pro Klasse • 1 Tabelle pro Verebungspfad Andreas Schmidt PHP (Teil 3) 21/33 Fakultät für Informatik & Wirtschaftsinformatik DB & IS II - WS 2016 Eine Tabelle pro Klassenhierarchie Person Kunde Angestellter Bodenpersonal Pilot Person id typ name vorname bonusmeilen eintrittsdatum sicherheitsstufe flugstunden 001 002 003 004 Vielflieg 600.000 Albatros NULL Sicher NULL Flugangst 10 K... P... B... K... Andreas Schmidt Sven Maria Sigi Andrea NULL 9.9.1980 1.8.1995 NULL NULL NULL E NULL NULL 20.000 NULL NULL PHP (Teil 3) 22/33 Fakultät für Informatik & Wirtschaftsinformatik DB & IS II - WS 2016 zugeh. DDL/DML-Statements create table Person ( id integer primary key, name varchar(40) not null, vorname varchar(40) not null, bonusmeilen integer, eintrittsdatum date, sicherheitsstufe integer, flugstunden integer, typ enum ('Kunde', 'Bodenpersonal', 'Pilot') ); insert into person (id, typ, vorname, name, bonusmeilen) values(1,'Kunde','Sven','Vielflieg',600000); insert into person (id, typ, vorname, name, eintrittsdatum, flugstunden) values(2,'Pilot','Maria','Albatros', '1980-9-9', 20000); Andreas Schmidt PHP (Teil 3) 23/33 Fakultät IWI DB & IS II - WS 2016 Eine Tabelle pro Klasse Person Kunde Angestellter Bodenpersonal Pilot Person id typ 001 Kunde Sven Vielflieg 002 Pilot Maria Albatros 003 Bodenpersonal Sigi 004 Kunde Kunde id_fk vorname name Sicher Andrea Flugangst Angestellter bonusmeilen id_fk eintrittsdatum 001 600.000 002 9.9.1980 004 12 003 1.8.1995 Bodenpersonal id_fk sicherheitsstufe 003 Andreas Schmidt E Pilot id_fk 002 flugstunden 20.000 PHP (Teil 3) 24/33 Fakultät für Informatik & Wirtschaftsinformatik DB & IS II - WS 2016 zugeh. DDL-Statements create table Person ( id integer primary key, name varchar(40) not null, vorname varchar(40) not null, typ enum ('Kunde', 'Bodenpersonal', 'Pilot') ); create table Kunde ( id_fk integer primary key, bonusmeilen integer, foreign key(id_fk) references Person(id) on delete cascade ); Andreas Schmidt create table Angestellter ( id_fk integer primary key, eintrittsdatum date, foreign key(id_fk) references Person(id) on delete cascade ); create table Bodenpersonal ( id_fk integer primary key, sicherheitsstufe integer, foreign key(id_fk) references Angestellter(id_fk) on delete cascade ); create table Pilot ( id_fk integer primary key, flugstunden integer, foreign key(id_fk) references Angestellter(id_fk) on delete cascade ); PHP (Teil 3) 25/33 Fakultät für Informatik & Wirtschaftsinformatik DB & IS II - WS 2016 zugeh. DML-Statements insert into person (id, vorname, name, typ) values(1,'Sven','Vielflieg','Kunde'); insert into kunde (id_fk, bonusmeilen) values(1, 600000); insert into person (id, vorname, name, typ) values(2,'Maria','Albatros','Pilot'); insert into angestellter (id_fk, eintrittsdatum) values (2,'1980-9-9'); insert into pilot (id_fk, flugstunden) values (2,20000); Andreas Schmidt PHP (Teil 3) 26/33 Fakultät IWI DB & IS II - WS 2016 Eine Tabelle pro Vererbungspfad Person Kunde Angestellter Bodenpersonal Pilot Kunde id name vorname bonusmeilen 001 Sven Vielflieg 600.000 004 Andrea Flugangst 12 Bodenpersonal id name 003 Sigi vorname Sicher eintrittsdatum 1.8.1995 sicherheitsstufe E Pilot id 002 name Maria Andreas Schmidt vorname Albatros eintrittsdatum 9.9.1980 flugstunden 20.000 PHP (Teil 3) 27/33 Fakultät für Informatik & Wirtschaftsinformatik DB & IS II - WS 2016 zugeh. DDL/DML-Statements create table Kunde ( id integer primary key, name varchar(40) not null, vorname varchar(40) not null, bonusmeilen integer ); create table Bodenpersonal ( id integer primary key, name varchar(40) not null, vorname varchar(40) not null, eintrittsdatum date, sicherheitsstufe integer ); insert into kunde (id, vorname, name, bonusmeilen) values(1,'Sven','Vielflieg',600000); insert into pilot (id, vorname, name, eintrittsdatum, flugstunden) values(2,'Maria','Albatros','1980-9-9',20000); create table Pilot ( id integer primary key, name varchar(40) not null, vorname varchar(40) not null, eintrittsdatum date, flugstunden integer ); Andreas Schmidt PHP (Teil 3) 28/33 Fakultät für Informatik & Wirtschaftsinformatik DB & IS II - WS 2016 Methoden • Statische Methoden: • Instanzenmethoden $pe $ku $bo $pi $p->getType() // liefert Typname zurück = = = = Person::create($name, $vorname) Kunde::create(..., $bonusmeilen) Bodenpersonal::create(...) Pilot::create(...) $p->hasType($type) $px = Person::get(...) // // // // true, falls der Typ von p dem von $type oder einem davon abgeleiteten entspricht $p->delete() $personen = Person::query($cond) $piloten = Pilot::query($cond) // Accessor + Mutatormethoden ... // Beziehungsmethoden ... Andreas Schmidt PHP (Teil 3) 29/33 Fakultät für Informatik & Wirtschaftsinformatik DB & IS II - WS 2016 Performanceüberlegungen • • • • • • • „Instant loading“ vs. „lazy loading“ „lazy object generation“ (proxy objects) „late execution“ von SQL-Update Statements Cache mit prepared-statements (z.B. Dictionary mit SQL-Statements als Key) Cache für Ergebnisse bei Beziehungen (Variante 2) Outer Join bei <0,1> Kardinalität Update nur auf geänderte Spalten Andreas Schmidt PHP (Teil 3) 30/33 Fakultät für Informatik & Wirtschaftsinformatik DB & IS II - WS 2016 application logic Views Controlers Business logic GUI OO-application logic Object-relational-Mapping Relational DBMS Andreas Schmidt PHP (Teil 3) 31/33 Fakultät für Informatik & Wirtschaftsinformatik DB & IS II - WS 2016 application logic • • • • • Applikationslogik wird in Schicht oberhalb der OR-Mapping Schicht realisiert Applikationslogik ist unabhängig von darunterliegender Datenbankschicht Frage: wie wird Applikationslogik ins System integriert ? Antwort: z.B. durch Unterklassenbildung (ableiten derCRUD-Klassen) Prinzip: class Film extends CRUD_Film { private ... function __construct(...) { parent::__construct(...); ... } // Methods of class Film // ... • Notwendige Änderungen an OR-Schicht: OR-Schicht darf nur Instanzen der abgeleiteten Klassen erzeugen Andreas Schmidt PHP (Teil 3) 32/33 Fakultät für Informatik & Wirtschaftsinformatik DB & IS II - WS 2016 application logic class Film extends CRUD_Film { // Realisierung der Applikationslogik unter Zuhilfenahme der Funktionalität // der durch die OR-Schicht bereitgestellte Funktionalität // ... function numberOfActors() { return count($this->getActors()); } // weitere Methoden ... } Hinweis: Aus Performancegründen ist hier eventuell doch die Ausführung eines SQL-Statements sinnvoll !! Andreas Schmidt PHP (Teil 3) 33/33