Relationale Datenbanken als persistenter Speicher
Grundsätzliches
- Pluspunkte
- Weit verbreitet, sehr zuverlässig
- sehr gute open source Datenbanken verfügbar
- Firmen haben sehr viel Geld in Software und Ausbildung investiert
- Daten sind ein sehr wichtiger Besitz von Firmen
- Kundendaten, Produktdaten, Mitarbeiter
- Daten „leben“ sehr lange (20 Jahre und mehr)
- keine Bereitschaft, Datenbanksysteme zu wechseln
- Nachteil
- Relationale Datenbanken passen nicht optimal zur objektorientierten Programmierung
- manche Objektstrukturen nicht effizient abbildbar → CAD-Systeme, Social Media …
- Relationale Datenbanken passen nicht optimal zur objektorientierten Programmierung
- In der Praxis
- Objekt-relationale Abbildungen sind weit verbreitet
- bei typischer Enterprise Software gut brauchbar
- Es gibt eine gute Unterstützung durch Programmbibliotheken bei JEE und Spring
- Spring und JEE verwenden die Java Persistence API (JPA)
- Spring verwendet standardmäßig das open source Framework Hibernate
- Non-SQL-Datenbanken gewinnen an Bedeutung
- OODBMS sind kaum im Einsatz
Objektrelationale Abbildungen
- Persistente Klassen
ORM im Beispielmodell - Jede Klasse wird in einer eigenen Tabelle dargestellt.
- Die Objektidentität wird durch einen synthetischen Schlüssel sichergestellt.
- Attribute werden wenn möglich als Spalten der Tabelle dargestellt.
- Attribute mit einem Klassentyp, die nicht direkt durch einen SQL-Datentyp abgebildet werden können, werden in eigene Tabellen abgebildet.
- Assoziationen
- 1:1 und 1:n Assoziation → Darstellung als Fremdschlüssel in der Datenbank.
- m:n Assoziation → Darstellung als Korrelationstabelle in der Datenbank.
- Vererbung
- 3 Varianten der Realisierung:
- Eine Tabelle pro Klassenhierarchie,
- eine Tabelle pro konkreter Klasse,
- eine Tabelle pro Klasse.
- 3 Varianten der Realisierung:
Realisierung im Code mit JPA Annotationen
- Klassen, die nicht in einer Vererbungshierarchie eingebunden sind (außer mit Object)
- Soll Klasse in die Datenbank abgeildet werden → @Entity
- Soll ein bestimmter Tabellenname verwendet werden → @Table( … )
- für Nameskonventionen (z.B. alle Tabellennamen fangen mit TBL_ an)
- Vermeiden reservierter Wörter (z.B. Union)
- default: Klassenname = Tabellenname
@Entity // markiert die Klasse für die Abbildung in DB @Table(name="TBL_PROJECT") // optionale Angabe der Tabelle public class Project { … } // Klassendefinition
- Attribute
- Jede Klasse braucht einen Primärschlüssel
- Empfohlen: semantikfreies Schlüsselattribut (sog. surrogate key)
- möglichst Schlüsselerzeugungsmechanismus des DBMS nutzen
-
@Id @GeneratedValue(strategy=GenerationType.IDENTITY) private Long id;
- Zugriff auf Attribute:
field
|method
- wird als default durch Position der
@Id
Annotation bestimmt:- vor Feld → field, vor getter → method
- kann individuell geändert werden
- JPA/Hibernate greift auch auf private Elemente zu (Bytecode Manipulation)
- wird als default durch Position der
- Komplexe Attribute
- Kompositionsbeziehung: Objekt wird in der Tabelle des besitzenden Objekts mit abgelegt
@Embedded
Annotation vor Attribut oder@Embeddable
Annotation vor der Klassendefinition des Attributs
- Assoziationen werden anders behandelt!
- Kompositionsbeziehung: Objekt wird in der Tabelle des besitzenden Objekts mit abgelegt
- Attribute, die nicht persistiert werden sollen, werden mit
@Transient
annotiert
- Jede Klasse braucht einen Primärschlüssel
- Assoziationen
- Assoziationen in JPA sind immer unidirektional, Beziehungen in einer relationalen Datenbank sind immer bidirektional abfragbar
- Wenn die Assoziation in Java bidirektional implementiert ist, muss das durch
mappedBy
angezeigt werden - Synchronisation der Assoziationsenden in Java muss im Java-Code erfolgen
- Beispiel 1 : n Beziehung: @JoinColumn definiert die Fremdschlüsselspalte
@ManyToOne @JoinColumn(name="Project_ID", nullable=false) private Project project;
@OneToMany(mappedBy = "project") private Set<Sprint> ssprint = new HashSet<Sprint>();
- Beispiel m : n Beziehung:
@JoinTable
definiert die Link-Tabelle mit Tabellenname und Spaltennamen@ManyToMany @JoinTable(name = "link_Sprint_Task", joinColumns = { @JoinColumn(name = "task_id") }, inverseJoinColumns = { @JoinColumn(name = "sprint_id") } ) private Set<Sprint> sprint= new HashSet<Sprint>();
@ManyToMany(mappedBy="backlog") private Set<Task> members = new HashSet<Task>();
- Beispiel 1 : n Beziehung: @JoinColumn definiert die Fremdschlüsselspalte
- Kaskadierung: Einfüge- und Löschoperationen können über Assoziationen hinweg auf die Objekte wirken
- Reduziert die Anzahl der save() bzw. delete-Aufrufe
- kann mit Hilfe der Annotationen definiert werden
- Hibernate-Annotationen sind weitergehend als JPA Annotationen
- Beispiel:
@ManyToMany @JoinTable(name = "link_Sprint_Task", joinColumns = { @JoinColumn(name = "task_id") }, inverseJoinColumns = { @JoinColumn(name = "sprint_id") } ) @Cascade(org.hibernate.annotations.CascadeType.SAVE_UPDATE); private Set<Sprint> sprint= new HashSet<Sprint>();
- Klassenhierarchien, Vererbung
- Drei unterschiedliche Strategien zur Abbildung der Objekte auf Tabellen:
SINGLE_TABLE
|JOINED
|TABLE_PER_CLASS
- Angabe in der obersten Basisklasse gilt für alle Subklassen
Strategie Single Table: Alle Klassen einer Vererbungshierarchie in einer Tabelle
- Performant, Polymorphismus einschließlich polymorpher Assoziationen einfach zu realisieren
- Verstoß gegen 3. Normalform
- Spalten von Kindklassen müssen nullable sein
@Entity @Inheritance(strategy = InheritanceType.SINGLE_TABLE) @DiscriminatorColumn(name="DTYPE", discriminatorType=DiscriminatorType.STRING) // optional public abstract class Task { @Id @GeneratedValue(strategy = GenerationType.AUTO) private Long id;
select * from task
Strategie Joined: Kindklassentabellen werden über Fremdschlüssel mit der Basisklasse verknüpft
- 3. Normalform ok, not null constraints möglich
- kleiner Performancenachteil, da auf mehrere Tabellen zugegriffen werden muss
- komplexere SQL Queries (nur bei direktem DB-Zugriff, nicht aus Java)
@Entity @Inheritance(strategy = InheritanceType.JOINED) public abstract class Task { @Id @GeneratedValue(strategy = GenerationType.AUTO) private Long id;
select * from task natural join compound_task
- Strategie Table per Class: Jede nichtabstrakte Klasse hat eigene Tabelle
- Probleme mit Polymorphismus, nicht empfehlenswert
- Lässt sich für das Beispielprojekt daher nicht ohne größere Änderungen demonstrieren
- Drei unterschiedliche Strategien zur Abbildung der Objekte auf Tabellen:
- Referenzen
- TopLink JPA Annotation Reference: JPA 2.1 Referenzimplementierung
- Hibernate Annotations
Aufgabe
Implementieren Sie die von Ihnen zum Klassenmodell hinzugefügten Domainklassen mit den für die persistente Speicherung notwendigen JPA Annotationen.