SlideShare a Scribd company logo
Effiziente Datenpersistierung
mit JPA 2.1 und Hibernate
JavaLand 2016
www.thoughts-on-java.org
ThorbenJanssen
• Independent author and trainer
• Senior developer and architect @ Qualitype GmbH
• CDI 2.0 expert group member
• Twitter: @thjanssen123
• Blog: www.thoughts-on-java.org
www.thoughts-on-java.org
Performance
www.thoughts-on-java.org
Performance
• Recognize performance problems as early as possible
• Typical causes for performance problems
• Solving performance problems
www.thoughts-on-java.org
Hibernate Statistics
www.thoughts-on-java.org
HibernateStatistics
• Activate via system property
• hibernate.generate_statistics = true
• Configure logging
• org.hibernate.stat = DEBUG
www.thoughts-on-java.org
HibernateStatistics
08:24:10,916 DEBUG
[org.hibernate.stat.internal.ConcurrentStatisticsImpl]
(default task-1) HHH000117: HQL: SELECT a FROM Author
a WHERE a.lastName = :lastName, time: 6ms, rows: 1
www.thoughts-on-java.org
Time
spend for
this query Number of
returned
rows
HibernateStatistics 08:08:04,960 INFO
[org.hibernate.engine.internal.StatisticalLoggingSessionEventListe
ner] (default task-2) Session Metrics {
1191522 nanoseconds spent acquiring 4 JDBC connections;
433875 nanoseconds spent releasing 4 JDBC connections;
4404058 nanoseconds spent preparing 6 JDBC statements;
12458725 nanoseconds spent executing 6 JDBC statements;
0 nanoseconds spent executing 0 JDBC batches;
0 nanoseconds spent performing 0 L2C puts;
0 nanoseconds spent performing 0 L2C hits;
0 nanoseconds spent performing 0 L2C misses;
586896 nanoseconds spent executing 1 flushes (flushing a total
of 2 entities and 2 collections);
39434974 nanoseconds spent executing 1 partial-flushes
(flushing a total of 2 entities and 2 collections)
www.thoughts-on-java.org
Number of SQL
statements
Cache usage
Time
spend
for SQL
state-
ments
Typical causes for performance
problems
www.thoughts-on-java.org
TypicalCauses
• Slow SELECT statements
• Wrong FetchType
• Load same data multiple times
www.thoughts-on-java.org
Slow SELECT-statements
www.thoughts-on-java.org
SlowSELECTs • In general no „real“ JPA or Hibernate problem
• Check generated SQL
• Check execution plan of the statement
• Check indexes
• Optimize SELECT statement
• Consider to use a native query
www.thoughts-on-java.org
NativeQuery • Reasons to use native queries:
• JPQL supports only a subset of SQL
• Database specific features
• Native queries return an Object[] for each row
• Needs to be mapped programmatically or declaratively
www.thoughts-on-java.org
ResultSetMapping • Declarative mapping of query results
www.thoughts-on-java.org
@SqlResultSetMapping(
name = "myResultMapping ",
entities = {@EntityResult(...), …},
classes = {@ConstructorResult (…), …},
columns = {@ColumnResult(…), …}
)
this.em.createNativeQuery(“Select …", "myResultMapping")
ResultSetMapping
www.thoughts-on-java.org
@SqlResultSetMapping(
name = "myResultMapping",
entities = {@EntityResult(
entityClass = Author.class,
fields = {
@FieldResult(name = "id", column = „autId"),
…}
),
…},
classes = {@ConstructorResult (…), …},
columns = {@ColumnResult(…), …}
)
ResultSetMapping
www.thoughts-on-java.org
@SqlResultSetMapping(
name = "myResultMapping",
entities = {@EntityResult(...), …},
classes = {@ConstructorResult(
targetClass = BookPublisherValue.class,
columns = {
@ColumnResult(name = "title"),
…}
),
…},
columns = {@ColumnResult(…), …}
)
ResultSetMapping
www.thoughts-on-java.org
@SqlResultSetMapping(
name = "myResultMapping",
entities = {@EntityResult(...), …},
classes = {@ConstructorResult(...), …},
columns = {@ColumnResult(
name = "bookCount",
type = Long.class),
…},
)
FetchType
www.thoughts-on-java.org
FetchType
• Defines when the relationship will be fetched
• Static definition in entity mapping
www.thoughts-on-java.org
@ManyToMany(mappedBy="authors", fetch = FetchType.EAGER)
private Set<Book> books;
FetchType • Lazy
• Relationship gets loaded at first access
• Default for to-many relationships
• Eager
• Loads relationships immediately
• Default for to-one relationships
www.thoughts-on-java.org
Recommendations • To-many relationships
• Stick to the default mapping (FetchType.LAZY)
• Use eager fetching for specific queries, if required
• To-one relationships
• Check individually
• Default is fine in most of the cases
www.thoughts-on-java.org
Query Specific Fetching
www.thoughts-on-java.org
N+1Select? • Most common cause for performance problems
• Lazy fetching of related entities creates too many queries
www.thoughts-on-java.org
List<Author> authors = this.em.createQuery("SELECT a FROM Author a",
Author.class).getResultList();
for (Author a : authors) {
System.out.println("Author " + a.getFirstName() + " " + a.getLastName()
+ " wrote " + a.getBooks().size() + “ Books.”));
}
Queryspecificfetching
• Fetch all required entities with one query
• Fetch Joins
• @NamedEntityGraph
• EntityGraph
www.thoughts-on-java.org
Fetch Join
www.thoughts-on-java.org
FetchJoin
• Use JOIN FETCH instead of JOIN in JPQL query
www.thoughts-on-java.org
List<Author> authors = this.em.createQuery(
"SELECT DISTINCT a FROM Author a JOIN FETCH a.books b",
Author.class).getResultList();
FetchJoin • Advantages
• Relationships gets loaded in same query
• Disadvantages
• Requires a special query for each use case
• Creates cartesian product
www.thoughts-on-java.org
NamedEntityGraph
www.thoughts-on-java.org
NamedEntityGraph • Introduced in JPA 2.1
• Declaratively defines a graph of entities which will be loaded
• Graph is query independent
www.thoughts-on-java.org
NamedEntityGraph • Define NamedEntityGraph
www.thoughts-on-java.org
@NamedEntityGraph(
name = "graph.AuthorBooksReviews",
attributeNodes =
@NamedAttributeNode(value = "books")
)
@NamedEntityGraph(
name = "graph.AuthorBooksReviews",
attributeNodes =
@NamedAttributeNode(value = "books", subgraph = "books"),
subgraphs =
@NamedSubgraph(
name = "books",
attributeNodes = @NamedAttributeNode("reviews")
)
)
NamedEntityGraph • Provide entity graph es hint
www.thoughts-on-java.org
EntityGraph graph = this.em.getEntityGraph("graph.AuthorBooks");
this.em.createQuery("SELECT DISTINCT a FROM Author a")
.setHint("javax.persistence.loadgraph", graph);
NamedEntityGraph • Fetch graph
• Eager loading for all elements of the graph
• Lazy loading for all other attributes
• Load graph
• Eager loading for all elements of the graph
• Loads all other attributes with their defined FetchType
• Hibernate always uses a load graph
• HHH-8776
www.thoughts-on-java.org
NamedEntityGraph • Advantages
• Query specific EAGER loading
• Definition of the graph is independent of the query
• Disadvantages
• Creates cartesian product
www.thoughts-on-java.org
EntityGraph
www.thoughts-on-java.org
EntityGraph • Introduced in JPA 2.1
• Dynamic version of @NamedEntityGraph
• Definition via Java API
• Graph is query independent
www.thoughts-on-java.org
EntityGraph • Define and use EntityGraph
www.thoughts-on-java.org
EntityGraph graph = this.em.createEntityGraph(Author.class);
Subgraph<Book> bookSubGraph = graph.addSubgraph(Author_.books);
bookSubGraph.addSubgraph(Book_.reviews);
this.em.createQuery("SELECT DISTINCT a FROM Author a")
.setHint("javax.persistence.loadgraph", graph);
EntityGraph • Advantages
• Query specific EAGER loading
• Definition of the graph is independent of the query
• Dynamic creation at runtime
• Disadvantages
• Creates cartesian product
www.thoughts-on-java.org
Caching
www.thoughts-on-java.org
Query
Cache
Caches
www.thoughts-on-java.org
DB
2nd
Level
Cache
1st
Level
Cache
Hibernate
Session
1st
Level
Cache
Hibernate
Session
1st Level Cache
www.thoughts-on-java.org
1stLevelCache
• Activated by default
• Linked to the Hibernate session
• Stores all entities that were used within a session
• Transparent usage
www.thoughts-on-java.org
2nd Level Cache
www.thoughts-on-java.org
2ndLevelCache • Session independent entity store
• Needs to be activated
• persistence.xml or EntityManagerFactory
• Transparent usage
• PersistenceProvider doesn‘t need to provide it
• Not always portable
www.thoughts-on-java.org
2ndLevelCache • Shared Cache Mode
• ALL cache all entities
• NONE cache no entities
• ENABLE_SELECTIVE cache needs to be activated for
specific entities
• DISABLE_SELECTIVE cache can be deactivated for specific
entities
• UNSPECIFIED use default settings of the
PersistenceProvider
www.thoughts-on-java.org
2ndLevelCache • Cache configuration
• Cache Retrieve Mode
• How to read entities from the cache
• Cache Store Mode
• How to write entities to the cache
• Concurrency Strategy
• How to handle concurrent access
www.thoughts-on-java.org
Query Cache
www.thoughts-on-java.org
QueryCache • Hibernate specific
• Stores query result session independent
• Needs to be activated (persistence.xml)
• hibernate.cache.use_query_cache = true
• Activate caching for a specific query
• org.hibernate.Query.setCacheable(true)
• @NamedQuery(… hints =
@QueryHint(name="org.hibernate.cacheable", value="true"))
www.thoughts-on-java.org
QueryCache • Stores query results for a query and its parameters
• [„FROM Author WHERE id=?“, 1]  [1]
• Stores only entity references or scalars
• Always use together with 2nd Level Cache
www.thoughts-on-java.org
Recommendations • Only cache data that is seldom updated
• Always benchmark the application when adding or changing
caching
• Use Query Cache together with 2nd Level Cache
• Configuration has to fit to each other
www.thoughts-on-java.org
Slides & Cheat Sheet
www.thoughts-on-java.org
Get this presentation and a handy cheat sheet:
http://www.thoughts-on-java.org/javaland2016/
Follow me on twitter:
@thjanssen123
www.thoughts-on-java.org
Resources
www.thoughts-on-java.org
Resources • JSR 338: JavaTM Persistence API, Version 2.1
http://download.oracle.com/otndocs/jcp/persistence-
2_1-fr-eval-spec/index.html
• Hibernate Reference Documentation
http://docs.jboss.org/hibernate/orm/4.3/manual/en-
US/html/
• Hibernate Developer Guide
http://docs.jboss.org/hibernate/orm/4.3/devguide/en-
US/html/
• Hibernate ORM: Tips, Tricks and Performance Techniques
by Brett Meyer
http://de.slideshare.net/brmeyer/hibernate-orm-
performance-31550150
www.thoughts-on-java.org
Resources • Java Persistence with Hibernate Second Edition by Christian
Bauer, Gaving King, Gary Gregory
• Java Platform, Enterprise Edition: The Java EE Tutorial
https://docs.oracle.com/javaee/7/tutorial/index.html
• Hibernate: Truly Understanding the Second-Level and
Query Caches
http://www.javalobby.org/java/forums/t48846.html
www.thoughts-on-java.org

More Related Content

Effiziente Datenpersistierung mit JPA 2.1 und Hibernate

  • 1. Effiziente Datenpersistierung mit JPA 2.1 und Hibernate JavaLand 2016 www.thoughts-on-java.org
  • 2. ThorbenJanssen • Independent author and trainer • Senior developer and architect @ Qualitype GmbH • CDI 2.0 expert group member • Twitter: @thjanssen123 • Blog: www.thoughts-on-java.org www.thoughts-on-java.org
  • 4. Performance • Recognize performance problems as early as possible • Typical causes for performance problems • Solving performance problems www.thoughts-on-java.org
  • 6. HibernateStatistics • Activate via system property • hibernate.generate_statistics = true • Configure logging • org.hibernate.stat = DEBUG www.thoughts-on-java.org
  • 7. HibernateStatistics 08:24:10,916 DEBUG [org.hibernate.stat.internal.ConcurrentStatisticsImpl] (default task-1) HHH000117: HQL: SELECT a FROM Author a WHERE a.lastName = :lastName, time: 6ms, rows: 1 www.thoughts-on-java.org Time spend for this query Number of returned rows
  • 8. HibernateStatistics 08:08:04,960 INFO [org.hibernate.engine.internal.StatisticalLoggingSessionEventListe ner] (default task-2) Session Metrics { 1191522 nanoseconds spent acquiring 4 JDBC connections; 433875 nanoseconds spent releasing 4 JDBC connections; 4404058 nanoseconds spent preparing 6 JDBC statements; 12458725 nanoseconds spent executing 6 JDBC statements; 0 nanoseconds spent executing 0 JDBC batches; 0 nanoseconds spent performing 0 L2C puts; 0 nanoseconds spent performing 0 L2C hits; 0 nanoseconds spent performing 0 L2C misses; 586896 nanoseconds spent executing 1 flushes (flushing a total of 2 entities and 2 collections); 39434974 nanoseconds spent executing 1 partial-flushes (flushing a total of 2 entities and 2 collections) www.thoughts-on-java.org Number of SQL statements Cache usage Time spend for SQL state- ments
  • 9. Typical causes for performance problems www.thoughts-on-java.org
  • 10. TypicalCauses • Slow SELECT statements • Wrong FetchType • Load same data multiple times www.thoughts-on-java.org
  • 12. SlowSELECTs • In general no „real“ JPA or Hibernate problem • Check generated SQL • Check execution plan of the statement • Check indexes • Optimize SELECT statement • Consider to use a native query www.thoughts-on-java.org
  • 13. NativeQuery • Reasons to use native queries: • JPQL supports only a subset of SQL • Database specific features • Native queries return an Object[] for each row • Needs to be mapped programmatically or declaratively www.thoughts-on-java.org
  • 14. ResultSetMapping • Declarative mapping of query results www.thoughts-on-java.org @SqlResultSetMapping( name = "myResultMapping ", entities = {@EntityResult(...), …}, classes = {@ConstructorResult (…), …}, columns = {@ColumnResult(…), …} ) this.em.createNativeQuery(“Select …", "myResultMapping")
  • 15. ResultSetMapping www.thoughts-on-java.org @SqlResultSetMapping( name = "myResultMapping", entities = {@EntityResult( entityClass = Author.class, fields = { @FieldResult(name = "id", column = „autId"), …} ), …}, classes = {@ConstructorResult (…), …}, columns = {@ColumnResult(…), …} )
  • 16. ResultSetMapping www.thoughts-on-java.org @SqlResultSetMapping( name = "myResultMapping", entities = {@EntityResult(...), …}, classes = {@ConstructorResult( targetClass = BookPublisherValue.class, columns = { @ColumnResult(name = "title"), …} ), …}, columns = {@ColumnResult(…), …} )
  • 17. ResultSetMapping www.thoughts-on-java.org @SqlResultSetMapping( name = "myResultMapping", entities = {@EntityResult(...), …}, classes = {@ConstructorResult(...), …}, columns = {@ColumnResult( name = "bookCount", type = Long.class), …}, )
  • 19. FetchType • Defines when the relationship will be fetched • Static definition in entity mapping www.thoughts-on-java.org @ManyToMany(mappedBy="authors", fetch = FetchType.EAGER) private Set<Book> books;
  • 20. FetchType • Lazy • Relationship gets loaded at first access • Default for to-many relationships • Eager • Loads relationships immediately • Default for to-one relationships www.thoughts-on-java.org
  • 21. Recommendations • To-many relationships • Stick to the default mapping (FetchType.LAZY) • Use eager fetching for specific queries, if required • To-one relationships • Check individually • Default is fine in most of the cases www.thoughts-on-java.org
  • 23. N+1Select? • Most common cause for performance problems • Lazy fetching of related entities creates too many queries www.thoughts-on-java.org List<Author> authors = this.em.createQuery("SELECT a FROM Author a", Author.class).getResultList(); for (Author a : authors) { System.out.println("Author " + a.getFirstName() + " " + a.getLastName() + " wrote " + a.getBooks().size() + “ Books.”)); }
  • 24. Queryspecificfetching • Fetch all required entities with one query • Fetch Joins • @NamedEntityGraph • EntityGraph www.thoughts-on-java.org
  • 26. FetchJoin • Use JOIN FETCH instead of JOIN in JPQL query www.thoughts-on-java.org List<Author> authors = this.em.createQuery( "SELECT DISTINCT a FROM Author a JOIN FETCH a.books b", Author.class).getResultList();
  • 27. FetchJoin • Advantages • Relationships gets loaded in same query • Disadvantages • Requires a special query for each use case • Creates cartesian product www.thoughts-on-java.org
  • 29. NamedEntityGraph • Introduced in JPA 2.1 • Declaratively defines a graph of entities which will be loaded • Graph is query independent www.thoughts-on-java.org
  • 30. NamedEntityGraph • Define NamedEntityGraph www.thoughts-on-java.org @NamedEntityGraph( name = "graph.AuthorBooksReviews", attributeNodes = @NamedAttributeNode(value = "books") ) @NamedEntityGraph( name = "graph.AuthorBooksReviews", attributeNodes = @NamedAttributeNode(value = "books", subgraph = "books"), subgraphs = @NamedSubgraph( name = "books", attributeNodes = @NamedAttributeNode("reviews") ) )
  • 31. NamedEntityGraph • Provide entity graph es hint www.thoughts-on-java.org EntityGraph graph = this.em.getEntityGraph("graph.AuthorBooks"); this.em.createQuery("SELECT DISTINCT a FROM Author a") .setHint("javax.persistence.loadgraph", graph);
  • 32. NamedEntityGraph • Fetch graph • Eager loading for all elements of the graph • Lazy loading for all other attributes • Load graph • Eager loading for all elements of the graph • Loads all other attributes with their defined FetchType • Hibernate always uses a load graph • HHH-8776 www.thoughts-on-java.org
  • 33. NamedEntityGraph • Advantages • Query specific EAGER loading • Definition of the graph is independent of the query • Disadvantages • Creates cartesian product www.thoughts-on-java.org
  • 35. EntityGraph • Introduced in JPA 2.1 • Dynamic version of @NamedEntityGraph • Definition via Java API • Graph is query independent www.thoughts-on-java.org
  • 36. EntityGraph • Define and use EntityGraph www.thoughts-on-java.org EntityGraph graph = this.em.createEntityGraph(Author.class); Subgraph<Book> bookSubGraph = graph.addSubgraph(Author_.books); bookSubGraph.addSubgraph(Book_.reviews); this.em.createQuery("SELECT DISTINCT a FROM Author a") .setHint("javax.persistence.loadgraph", graph);
  • 37. EntityGraph • Advantages • Query specific EAGER loading • Definition of the graph is independent of the query • Dynamic creation at runtime • Disadvantages • Creates cartesian product www.thoughts-on-java.org
  • 41. 1stLevelCache • Activated by default • Linked to the Hibernate session • Stores all entities that were used within a session • Transparent usage www.thoughts-on-java.org
  • 43. 2ndLevelCache • Session independent entity store • Needs to be activated • persistence.xml or EntityManagerFactory • Transparent usage • PersistenceProvider doesn‘t need to provide it • Not always portable www.thoughts-on-java.org
  • 44. 2ndLevelCache • Shared Cache Mode • ALL cache all entities • NONE cache no entities • ENABLE_SELECTIVE cache needs to be activated for specific entities • DISABLE_SELECTIVE cache can be deactivated for specific entities • UNSPECIFIED use default settings of the PersistenceProvider www.thoughts-on-java.org
  • 45. 2ndLevelCache • Cache configuration • Cache Retrieve Mode • How to read entities from the cache • Cache Store Mode • How to write entities to the cache • Concurrency Strategy • How to handle concurrent access www.thoughts-on-java.org
  • 47. QueryCache • Hibernate specific • Stores query result session independent • Needs to be activated (persistence.xml) • hibernate.cache.use_query_cache = true • Activate caching for a specific query • org.hibernate.Query.setCacheable(true) • @NamedQuery(… hints = @QueryHint(name="org.hibernate.cacheable", value="true")) www.thoughts-on-java.org
  • 48. QueryCache • Stores query results for a query and its parameters • [„FROM Author WHERE id=?“, 1]  [1] • Stores only entity references or scalars • Always use together with 2nd Level Cache www.thoughts-on-java.org
  • 49. Recommendations • Only cache data that is seldom updated • Always benchmark the application when adding or changing caching • Use Query Cache together with 2nd Level Cache • Configuration has to fit to each other www.thoughts-on-java.org
  • 50. Slides & Cheat Sheet www.thoughts-on-java.org
  • 51. Get this presentation and a handy cheat sheet: http://www.thoughts-on-java.org/javaland2016/ Follow me on twitter: @thjanssen123 www.thoughts-on-java.org
  • 53. Resources • JSR 338: JavaTM Persistence API, Version 2.1 http://download.oracle.com/otndocs/jcp/persistence- 2_1-fr-eval-spec/index.html • Hibernate Reference Documentation http://docs.jboss.org/hibernate/orm/4.3/manual/en- US/html/ • Hibernate Developer Guide http://docs.jboss.org/hibernate/orm/4.3/devguide/en- US/html/ • Hibernate ORM: Tips, Tricks and Performance Techniques by Brett Meyer http://de.slideshare.net/brmeyer/hibernate-orm- performance-31550150 www.thoughts-on-java.org
  • 54. Resources • Java Persistence with Hibernate Second Edition by Christian Bauer, Gaving King, Gary Gregory • Java Platform, Enterprise Edition: The Java EE Tutorial https://docs.oracle.com/javaee/7/tutorial/index.html • Hibernate: Truly Understanding the Second-Level and Query Caches http://www.javalobby.org/java/forums/t48846.html www.thoughts-on-java.org