Download - Optimierung von JPA-Anwendungen
![Page 1: Optimierung von JPA-Anwendungen](https://reader034.vdocuments.pub/reader034/viewer/2022052304/558a1993d8b42a91448b4668/html5/thumbnails/1.jpg)
Optimierung von JPA-Anwendungen
Java User Group Berlin Brandenburg, 31.01.2013
Dirk Weil, GEDOPLAN GmbH
![Page 2: Optimierung von JPA-Anwendungen](https://reader034.vdocuments.pub/reader034/viewer/2022052304/558a1993d8b42a91448b4668/html5/thumbnails/2.jpg)
Dirk Weil
GEDOPLAN GmbH, Bielefeld
Java EE seit 1998
Konzeption undRealisierung
Vorträge
Seminare
Veröffentlichungen
![Page 3: Optimierung von JPA-Anwendungen](https://reader034.vdocuments.pub/reader034/viewer/2022052304/558a1993d8b42a91448b4668/html5/thumbnails/3.jpg)
Optimierung von JPA-Anwendungen
3
Laufzeit
Memory
Providerunabhängig
EclipseLink
Hibernate
…
![Page 4: Optimierung von JPA-Anwendungen](https://reader034.vdocuments.pub/reader034/viewer/2022052304/558a1993d8b42a91448b4668/html5/thumbnails/4.jpg)
Id-Generierung
Entity-Klassen müssen Id haben
PK in der DB
Feld oderPropertymit @Id
Empfehlenswert: Technische Id
Problem: Erzeugung eindeutiger Werte
4
@Entitypublic class SomeEntity{
@Idprivate int id;…
![Page 5: Optimierung von JPA-Anwendungen](https://reader034.vdocuments.pub/reader034/viewer/2022052304/558a1993d8b42a91448b4668/html5/thumbnails/5.jpg)
Id-Generierung
JPA-Feature: @GeneratedValue
Nutzt DB-Sequenzen,Identity Columns oderSequenz-Tabellen
Probleme:
Id erst nach persist gesetzt� equals ?, hashCode ?
Id-Übernahme kostet Zeit
5
@Id@GeneratedValueprivate int id;
![Page 6: Optimierung von JPA-Anwendungen](https://reader034.vdocuments.pub/reader034/viewer/2022052304/558a1993d8b42a91448b4668/html5/thumbnails/6.jpg)
Id-Generierung
Alternative: BYO-ID (selbst machen)
Id auch in transitiven Objekten gesetzt
Insert ohne Zusatzaufwand
Achtung: i. A. nicht trivial
Z. B.: UUID
6
@Idprivate String id
= new com.eaio.uuid.UUID().toString();
![Page 7: Optimierung von JPA-Anwendungen](https://reader034.vdocuments.pub/reader034/viewer/2022052304/558a1993d8b42a91448b4668/html5/thumbnails/7.jpg)
Id-Generierung
@GeneratedValue signifikant langsamer(OOTB)
7
Derby
EclipseLink
MySQL
EclipseLink
Oracle
EclipseLink
Derby
Hibernate
MySQL
Hibernate
Oracle
Hibernate
BYO-ID 19.864 11.659 22.478 19.240 9.684 7.126
AUTO 21.034 13.537 23.663 74.804 12.214 70.814
0
10.000
20.000
30.000
40.000
50.000
60.000
70.000
80.000
Mil
lise
ku
nd
en
Insert 50.000 einfache Entries
in 1.000er Batches
![Page 8: Optimierung von JPA-Anwendungen](https://reader034.vdocuments.pub/reader034/viewer/2022052304/558a1993d8b42a91448b4668/html5/thumbnails/8.jpg)
Id-Generierung
Tuning: Höhere Allocation Size
Leider nicht verfügbar bei IDENTITY
8
@Id@GeneratedValue(strategy = GenerationType. SEQUENCE,
generator = "ArtikelIdGenerator")@SequenceGenerator (name = "ArtikelIdGenerator",
allocationSize = 1000 )private int id;@Id
@GeneratedValue(strategy = GenerationType. TABLE,generator = "ArtikelIdGenerator")
@TableGenerator (name = "ArtikelIdGenerator",allocationSize = 1000 )
private int id;
![Page 9: Optimierung von JPA-Anwendungen](https://reader034.vdocuments.pub/reader034/viewer/2022052304/558a1993d8b42a91448b4668/html5/thumbnails/9.jpg)
Id-Generierung
9
0
10.000
20.000
30.000
40.000
50.000
60.000
70.000
80.000
1 10 100 1000
Laufzeit vs. Allocation Size
![Page 10: Optimierung von JPA-Anwendungen](https://reader034.vdocuments.pub/reader034/viewer/2022052304/558a1993d8b42a91448b4668/html5/thumbnails/10.jpg)
Relationship Loading
Relationen werden durch Felder mit @OneToOne, …, @ManyToManyrepräsentiert
10
@Entitypublic class Book{
@ManyToOnepublic Publisher publisher;
@Entitypublic class Publisher{
@OneToMany(mappedBy="publisher")public List<Book> books;
![Page 11: Optimierung von JPA-Anwendungen](https://reader034.vdocuments.pub/reader034/viewer/2022052304/558a1993d8b42a91448b4668/html5/thumbnails/11.jpg)
Relationship Loading
Relationen-Parameter: fetch
Referenzierte Entities direkt laden?
EAGER: Direkt
LAZY: Später bei Bedarf
11
@ManyToOne(fetch = FetchType.LAZY )private Artikel artikel;
![Page 12: Optimierung von JPA-Anwendungen](https://reader034.vdocuments.pub/reader034/viewer/2022052304/558a1993d8b42a91448b4668/html5/thumbnails/12.jpg)
Relationship Loading
Bsp.: Auftragsposition bearbeiten
Ist Owner der n:1-Relation zu Artikel
12
Kunde Auftrag
AuftragsPosition
ArtikelLand
1 *
1*
*1
1*
@Entitypublic class AuftragsPosition{
@ManyToOneprivate Artikel artikel;
![Page 13: Optimierung von JPA-Anwendungen](https://reader034.vdocuments.pub/reader034/viewer/2022052304/558a1993d8b42a91448b4668/html5/thumbnails/13.jpg)
Relationship Loading
Annahme:Verwendet nurAuftragsPosition
13
AuftragsPosition aufPos= em.find(AuftragsPosition.class, id);…
select …from AuftragsPositionwhere …
select …from AuftragsPositionleft outer join Artikelwhere …
@ManyToOneprivate Artikel artikel;
@ManyToOne(fetch=FetchType.LAZY )private Artikel artikel;
![Page 14: Optimierung von JPA-Anwendungen](https://reader034.vdocuments.pub/reader034/viewer/2022052304/558a1993d8b42a91448b4668/html5/thumbnails/14.jpg)
Relationship Loading
Annahme:Verwendet auchArtikel
14
AuftragsPosition aufPos= em.find(AuftragsPosition.class, id);Artikel artikel = aufPos.getArtikel();…
select … from AuftragsPosition where …
select … from Artikel where …
select …from AuftragsPositionleft outer join Artikelwhere …
@ManyToOneprivate Artikel artikel;
@ManyToOne(fetch=FetchType.LAZY )private Artikel artikel;
![Page 15: Optimierung von JPA-Anwendungen](https://reader034.vdocuments.pub/reader034/viewer/2022052304/558a1993d8b42a91448b4668/html5/thumbnails/15.jpg)
Relationship Loading
Bsp.: Kunde bearbeiten
Ist Owner der 1:n-Relation zu Auftrag
15
Kunde Auftrag
AuftragsPosition
ArtikelLand
1 *
1*
*1
1*
@Entitypublic class Kunde{
@OneToMany(mappedBy="kunde")private Set<Auftrag> auftraege;
![Page 16: Optimierung von JPA-Anwendungen](https://reader034.vdocuments.pub/reader034/viewer/2022052304/558a1993d8b42a91448b4668/html5/thumbnails/16.jpg)
Relationship Loading
Annahme:Verwendetnur Kunde
16
Kunde kunde= em.find(Kunde.class, id);…
select …from Kundewhere …
select …from Kundeleft outer join Auftragleft outer join AuftragsPosition where …
@ManyToOne(fetch=FetchType.EAGER )private Set<Auftrag> auftraege;
@ManyToOneprivate Set<Auftrag> auftraege;
![Page 17: Optimierung von JPA-Anwendungen](https://reader034.vdocuments.pub/reader034/viewer/2022052304/558a1993d8b42a91448b4668/html5/thumbnails/17.jpg)
Relationship Loading
Messergebnis(1000 Interationen, Hibernate, MySQL)
17
EAGER LAZY
Nur AuftragsPosition 2.967 ms 2.505 ms - 15 %
Auch Artikel 2.959 ms 4.305 ms + 45 %
Nur Kunde 30.295 ms 4.848 ms - 84 %
= Default-Einstellung
![Page 18: Optimierung von JPA-Anwendungen](https://reader034.vdocuments.pub/reader034/viewer/2022052304/558a1993d8b42a91448b4668/html5/thumbnails/18.jpg)
Relationship Loading
Fazit:
Zugriffsverhalten genau analysieren
Default ist schon recht gut
Besser: Immer LAZY verwendenund bei Bedarf Fetch Joins nutzen
18
![Page 19: Optimierung von JPA-Anwendungen](https://reader034.vdocuments.pub/reader034/viewer/2022052304/558a1993d8b42a91448b4668/html5/thumbnails/19.jpg)
Relationship Loading
Fetch Joins mit JPQL
leider nur einstufig erlaubt
19
select ap from Auftragsposition apleft fetch join ap.artikel...
![Page 20: Optimierung von JPA-Anwendungen](https://reader034.vdocuments.pub/reader034/viewer/2022052304/558a1993d8b42a91448b4668/html5/thumbnails/20.jpg)
Relationship Loading
Fetch Joins mit Criteria Query
20
CriteriaQuery<Auftrag> cQuery= builder.createQuery(Auftrag.class);
Root<Auftrag> a= cQuery.from(Auftrag.class);
a. fetch (Auftrag_.auftragsPositionen). fetch (AuftragsPosition_.artikel);
…
![Page 21: Optimierung von JPA-Anwendungen](https://reader034.vdocuments.pub/reader034/viewer/2022052304/558a1993d8b42a91448b4668/html5/thumbnails/21.jpg)
Basic Attribute Loading
Fetch-Strategie auch für einfache Werte wählbar
Lazy Loading sinnvoll bei
selten genutzten Werten
umfangreichen Daten
21
@Basic( fetch = FetchType.LAZY )private String longAdditionalInfo;
![Page 22: Optimierung von JPA-Anwendungen](https://reader034.vdocuments.pub/reader034/viewer/2022052304/558a1993d8b42a91448b4668/html5/thumbnails/22.jpg)
Basic Attribute Loading
Messergebnis
Lesen von Kunden
10 'ungenutzte' Strings à 150 chars
1000 Interationen, EclipseLink, Oracle
22
EAGER LAZY
7.204 ms 6.820 ms -5 %
= Default-Einstellung
![Page 23: Optimierung von JPA-Anwendungen](https://reader034.vdocuments.pub/reader034/viewer/2022052304/558a1993d8b42a91448b4668/html5/thumbnails/23.jpg)
Lazy-Load-Verfahren
Proxy
23
@OneToManyprivate Set<Auftrag> auftraege
get(…)
?DB
![Page 24: Optimierung von JPA-Anwendungen](https://reader034.vdocuments.pub/reader034/viewer/2022052304/558a1993d8b42a91448b4668/html5/thumbnails/24.jpg)
Lazy-Load-Verfahren
Instrumentierung
24
@Basic(fetch = FetchType.LAZY)private String longAdditionalInfo;
get(…)?
DB
![Page 25: Optimierung von JPA-Anwendungen](https://reader034.vdocuments.pub/reader034/viewer/2022052304/558a1993d8b42a91448b4668/html5/thumbnails/25.jpg)
Bytecode-Instrumentierung
25
� = Standard
� = Providerspezifische Konfiguration erforderlich
EclipselinkVerfahren SE EE
@Basic Entity Instrumentation � �
@xxxToOne Entity Instrumentation � �
@xxxToMany Collection Proxy � �
HibernateVerfahren SE EE
@Basic Entity Instrumentation � �
@xxxToOne Attribute Proxy � �
@xxxToMany Collection Proxy � �
![Page 26: Optimierung von JPA-Anwendungen](https://reader034.vdocuments.pub/reader034/viewer/2022052304/558a1993d8b42a91448b4668/html5/thumbnails/26.jpg)
JPA Provider
Caching
26
EntityManager
DB
2nd
LevelCache
1st
LevelCache
QueryCache
![Page 27: Optimierung von JPA-Anwendungen](https://reader034.vdocuments.pub/reader034/viewer/2022052304/558a1993d8b42a91448b4668/html5/thumbnails/27.jpg)
First Level Cache
Standard
Je EntityManager
Enthält in Sitzung geladene Objekte
Achtung: Speicherbedarf!
ggf. explizit entlasten (clear , detach )
27
EntityManager
1st
LevelCache
![Page 28: Optimierung von JPA-Anwendungen](https://reader034.vdocuments.pub/reader034/viewer/2022052304/558a1993d8b42a91448b4668/html5/thumbnails/28.jpg)
First Level Cache
Arbeitetsitzungs-bezogen
28
// Kunden mit bestimmter Id ladenEntityManager em1 = emf.createEntityManager();Kunde k1 = em1.find(Kunde.class, id);
// Gleichen Kunden in 2. Session verändernEntityManager em2 = emf.createEntityManager();em2.getTransaction().begin();Kunde k2 = em2.find(Kunde.class, id);k2.setName("…");em2.getTransaction().commit();
// Gleichen Kunden in 1. Session erneut ladenKunde k3 = em1.find(Kunde.class, id);// ist unverändert!
![Page 29: Optimierung von JPA-Anwendungen](https://reader034.vdocuments.pub/reader034/viewer/2022052304/558a1993d8b42a91448b4668/html5/thumbnails/29.jpg)
First Level Cache
HashMap-Semantik
benötigt Key
wird für Queries nicht benutzt
29
// Kunden mit bestimmter Id ladenEntityManager em = emf.createEntityManager();Kunde k1 = em.find(Kunde.class, id);
// Query nach gleichem Kunden geht erneut zur DB!Kunde k2 = em.createQuery("select k from Kunde k " +
"where k.id=:id", Kunde.class).setParameter("id", id).getSingleResult();
![Page 30: Optimierung von JPA-Anwendungen](https://reader034.vdocuments.pub/reader034/viewer/2022052304/558a1993d8b42a91448b4668/html5/thumbnails/30.jpg)
Query Cache
Provider-spezifisch
Speichert Result Set IDs zu Queries
30
TypedQuery<Kunde> query= em.createQuery( "select k from Kunde k where k.name=:name" ,
Kunde.class);query.setParameter("name", "OPQ GbR" );… // Query Cache einschaltenKunde kunde = query.getSingleResult();
["select k from Kunde k where k.name=:name" , "OPQ GbR" ] � [id1 ]
![Page 31: Optimierung von JPA-Anwendungen](https://reader034.vdocuments.pub/reader034/viewer/2022052304/558a1993d8b42a91448b4668/html5/thumbnails/31.jpg)
Query Cache
Trotz mehrfacher Querynur ein DB-Zugriff
31
while (…){
TypedQuery<Kunde> query= em.createQuery("select k from Kunde k where k.name=:name",
Kunde.class);query.setParameter("name", "OPQ GbR");query.setHint(…) // Query Cache einschalten (providerabh.!)Kunde kunde = query.getSingleResult();…
}
![Page 32: Optimierung von JPA-Anwendungen](https://reader034.vdocuments.pub/reader034/viewer/2022052304/558a1993d8b42a91448b4668/html5/thumbnails/32.jpg)
Query Cache
EclipseLink
Hibernate:
(Aktivierung in der Konfiguration notwendig)
32
TypedQuery<Kunde> query = em.createQuery(…);query.setHint("org.hibernate.cacheable", true);…
TypedQuery<Kunde> query = em.createQuery(…);query.setHint("eclipselink.cache-usage",
"CheckCacheThenDatabase");…
![Page 33: Optimierung von JPA-Anwendungen](https://reader034.vdocuments.pub/reader034/viewer/2022052304/558a1993d8b42a91448b4668/html5/thumbnails/33.jpg)
Second Level Cache
JPA 2.0 unterstützt 2nd Level Cache
nur rudimentäre Konfiguration
ProviderspezifischeKonfigurationin der Praxisunabdingbar
33
JPA ProviderEntityManager
2nd
LevelCache
1st
LevelCache
![Page 34: Optimierung von JPA-Anwendungen](https://reader034.vdocuments.pub/reader034/viewer/2022052304/558a1993d8b42a91448b4668/html5/thumbnails/34.jpg)
Second Level Cache
Providerspezifische Implementierung
Cache-Provider Infinispan, EHCache, OSCache, …
Cache-Strategienread-only, read-write, …
StorageMemory, Disk, Cluster, …
34
![Page 35: Optimierung von JPA-Anwendungen](https://reader034.vdocuments.pub/reader034/viewer/2022052304/558a1993d8b42a91448b4668/html5/thumbnails/35.jpg)
Second Level Cache
Wirkt applikationsweit
Semantik ähnlich HashMap
Ladereihenfolge:
1st Level Cache (EntityManager)
2nd Level Cache, falls enabled
DB
35
![Page 36: Optimierung von JPA-Anwendungen](https://reader034.vdocuments.pub/reader034/viewer/2022052304/558a1993d8b42a91448b4668/html5/thumbnails/36.jpg)
Second Level Cache
Vorteil bei häufig genutzten Daten
Konstanten
selten veränderte Daten
nur von dieser Anwendung veränderte Daten
36
![Page 37: Optimierung von JPA-Anwendungen](https://reader034.vdocuments.pub/reader034/viewer/2022052304/558a1993d8b42a91448b4668/html5/thumbnails/37.jpg)
Second Level Cache
Bsp.: Stammdaten-Entity Land
wird n:1 von Kundereferenziert
nur wenige Land -Werte
Länder ändern sich nahezu nie
Länder können dauerhaft im Cache verbleiben
37
Kunde
Land
1*
![Page 38: Optimierung von JPA-Anwendungen](https://reader034.vdocuments.pub/reader034/viewer/2022052304/558a1993d8b42a91448b4668/html5/thumbnails/38.jpg)
Second Level Cache
Konfiguration lt. Spec
38
<persistence-unit name="…"><provider>…</provider><shared-cache-mode>ENABLE_SELECTIVE</shared-cache-mode>…
Cache aktiv für …
ALL alle Entities
NONE keine Klasse
ENABLE_SELECTIVE nur @Cacheable(true)
DISABLE_SELECTIVE alle außer @Cacheable(false)
@Entity@Cacheable(true)public class Land{
…
![Page 39: Optimierung von JPA-Anwendungen](https://reader034.vdocuments.pub/reader034/viewer/2022052304/558a1993d8b42a91448b4668/html5/thumbnails/39.jpg)
Second Level Cache
EclipseLink
Default: DISABLE_SELECTIVE
Hibernate bis Version 3.x
ignoriert Standard-Konfig
benötigt eigene Annotation
39
@Entity@Cache(usage = CacheConcurrencyStrategy.READ_ONLY)public class Land{
…
![Page 40: Optimierung von JPA-Anwendungen](https://reader034.vdocuments.pub/reader034/viewer/2022052304/558a1993d8b42a91448b4668/html5/thumbnails/40.jpg)
Second Level Cache
Messergebnis(1000 Interationen, EclipseLink, Oracle)
ohne 2nd Level Cache: 10.883 msmit 2nd Level Cache für Land: 6.549 ms
40
![Page 41: Optimierung von JPA-Anwendungen](https://reader034.vdocuments.pub/reader034/viewer/2022052304/558a1993d8b42a91448b4668/html5/thumbnails/41.jpg)
Paginierung
Queries mit großer Ergebnismenge'häppchenweise' verarbeiten
41
TypedQuery<Artikel> query= em.createQuery("select a from Artikel a", Artikel.class);query.setFirstResult(50);query.setMaxResults(10);List<Artikel> result = query.getResultList();
select …from Artikelwhere … and rownum>=50 and rownum<60
![Page 42: Optimierung von JPA-Anwendungen](https://reader034.vdocuments.pub/reader034/viewer/2022052304/558a1993d8b42a91448b4668/html5/thumbnails/42.jpg)
Paginierung
Eingeschränkt oder effektlos bei 1:n/m:n-Relationen mit:
Eager Loading
Fetch Joins
Join erzeugt kartesisches Produkt
Providerabhängige Lösung:
Ausführung im Memory
Ausführung mehrerer SQL-Befehle
42
![Page 43: Optimierung von JPA-Anwendungen](https://reader034.vdocuments.pub/reader034/viewer/2022052304/558a1993d8b42a91448b4668/html5/thumbnails/43.jpg)
Inheritance
Mehrere Abbildungen denkbar:
Alles in einer Tabelle
Eine Tabelle pro Klasse
Eine Tabelle pro konkreter Klasse
Strategie-Auswahl mit @Inheritance
43
<abstract>
Vehicle
Car Ship
![Page 44: Optimierung von JPA-Anwendungen](https://reader034.vdocuments.pub/reader034/viewer/2022052304/558a1993d8b42a91448b4668/html5/thumbnails/44.jpg)
Inheritance
SINGLE_TABLE
44
@Entity@Inheritance(strategy=InheritanceType.SINGLE_TABLE)public abstract class Vehicle{
…
![Page 45: Optimierung von JPA-Anwendungen](https://reader034.vdocuments.pub/reader034/viewer/2022052304/558a1993d8b42a91448b4668/html5/thumbnails/45.jpg)
Inheritance
JOINED
45
@Entity@Inheritance(strategy=InheritanceType.JOINED)public abstract class Vehicle{
…
![Page 46: Optimierung von JPA-Anwendungen](https://reader034.vdocuments.pub/reader034/viewer/2022052304/558a1993d8b42a91448b4668/html5/thumbnails/46.jpg)
Inheritance
TABLE_PER_CLASS
46
@Entity@Inheritance(strategy=InheritanceType.TABLE_PER_CLASS)public abstract class Vehicle{
…
![Page 47: Optimierung von JPA-Anwendungen](https://reader034.vdocuments.pub/reader034/viewer/2022052304/558a1993d8b42a91448b4668/html5/thumbnails/47.jpg)
Inheritance
Laufzeitvergleich für Queries
auf Basisklasse
auf abgeleitete Klasse
(1000 Iterationen, Ergebnis ca. 100 Einträge, Hibernate, MySQL)
47
SINGLE_TABLE
TABLE_PER_CLASS
JOINED
Basisklasse 2.705 ms 29.359 ms 3.434 ms
Subklasse 2.505 ms 1.435 ms 3.377 ms
![Page 48: Optimierung von JPA-Anwendungen](https://reader034.vdocuments.pub/reader034/viewer/2022052304/558a1993d8b42a91448b4668/html5/thumbnails/48.jpg)
Inheritance
Optimale Performanz liefernSINGLE_TABLEund TABLE_PER_CLASS
Aber: Auch andere Implikationen
Genaue Analyse notwendig
48
![Page 49: Optimierung von JPA-Anwendungen](https://reader034.vdocuments.pub/reader034/viewer/2022052304/558a1993d8b42a91448b4668/html5/thumbnails/49.jpg)
Providerabhängiges
Batch Size
Lazy-Varianten
Cache-Strategien
Prepared Statement Cache
49
![Page 50: Optimierung von JPA-Anwendungen](https://reader034.vdocuments.pub/reader034/viewer/2022052304/558a1993d8b42a91448b4668/html5/thumbnails/50.jpg)
Providerabhängiges
Load Groups
Change Detection
DB Dialects
…
50
![Page 51: Optimierung von JPA-Anwendungen](https://reader034.vdocuments.pub/reader034/viewer/2022052304/558a1993d8b42a91448b4668/html5/thumbnails/51.jpg)
Fazit
Viele Optimierungen providerunabhängig möglich
Wesentlich:
Lazy Loading
Caching
Genaue Analyse notwendig
Messen
Kein Selbstzweck
51