SlideShare a Scribd company logo
@vlad_mihalcea vladmihalcea.com
JPA and Hibernate
Performance Tips
@vlad_mihalcea vladmihalcea.com
About me
vladmihalcea.com
@vlad_mihalcea vladmihalcea.com
Mappings
CC BY-SA 2.0 - https://www.flickr.com/photos/47515486@N05/44129053595/
@vlad_mihalcea vladmihalcea.com
TABLE generator
@Entity
public class Post {
@Id
@GeneratedValue(strategy = GenerationType.TABLE)
private Long id;
private String title;
//Getters and setters omitted for brevity
}
@vlad_mihalcea vladmihalcea.com
TABLE generator
CREATE TABLE hibernate_sequences (
sequence_name (255) NOT NULL,
next_val,
PRIMARY KEY (sequence_name)
)
CREATE TABLE post (
id NOT NULL,
title (255),
PRIMARY KEY (id)
)
@vlad_mihalcea vladmihalcea.com
TABLE generator
public IntegralDataTypeHolder getNextValue() {
return session.getTransactionCoordinator().createIsolationDelegate()
.delegateWork(new AbstractReturningWork<IntegralDataTypeHolder>() {
public IntegralDataTypeHolder execute(
Connection connection) throws SQLException {
…
}, true
);
}
for (int i = 0; i < 3; i++) {
Post post = new Post();
post.setTitle(
String.format("High-Performance Java Persistence, Part %d", i + 1)
);
entityManager.persist(post);
}
@vlad_mihalcea vladmihalcea.com
SELECT tbl.next_val FROM hibernate_sequences tbl
WHERE tbl.sequence_name = 'default' FOR UPDATE
INSERT INTO hibernate_sequences (sequence_name, next_val) VALUES ('default', 1)
UPDATE hibernate_sequences SET next_val = 2
WHERE next_val = 1 AND sequence_name = 'default'
SELECT tbl.next_val FROM hibernate_sequences tbl
WHERE tbl.sequence_name = 'default' FOR UPDATE
UPDATE hibernate_sequences SET next_val = 3
WHERE next_val = 2 AND sequence_name = 'default'
SELECT tbl.next_val FROM hibernate_sequences tbl
WHERE tbl.sequence_name = 'default' FOR UPDATE
UPDATE hibernate_sequences SET next_val = 4
WHERE next_val = 3 AND sequence_name = 'default'
TABLE generator
@vlad_mihalcea vladmihalcea.com
INSERT INTO post (title, id)
VALUES ('High-Performance Java Persistence, Part 1', 1)
INSERT INTO post (title, id)
VALUES ('High-Performance Java Persistence, Part 2', 2)
INSERT INTO post (title, id)
VALUES ('High-Performance Java Persistence, Part 3', 3)
TABLE generator
@vlad_mihalcea vladmihalcea.com
IDENTITY vs TABLE generator
@vlad_mihalcea vladmihalcea.com
SEQUENCE vs TABLE generator
@vlad_mihalcea vladmihalcea.com
AUTO Generator
@Entity
public class Post {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String title;
//Getters and setters omitted for brevity
}
@vlad_mihalcea vladmihalcea.com
AUTO Generator
• Prior to Hibernate 5 – native strategy.
• Hibernate 5 – SequenceStyleGenerator strategy (falls back to
TABLE)
@vlad_mihalcea vladmihalcea.com
AUTO Generator – Hibernate 5 and MySQL
@Id
@GeneratedValue(generator="native")
@GenericGenerator(name = "native", strategy = "native")
private Long id;
INSERT INTO post (title)
VALUES ('High-Performance Java Persistence, Part 1')
INSERT INTO post (title)
VALUES ('High-Performance Java Persistence, Part 2')
INSERT INTO post (title)
VALUES ('High-Performance Java Persistence, Part 3')
@vlad_mihalcea vladmihalcea.com
Identifier portability – annotation mapping
@Entity(name = "Post")
@Table(name = "post")
public class Post {
@Id
@GeneratedValue(generator = "sequence",
strategy = GenerationType.SEQUENCE)
@SequenceGenerator(name = "sequence", allocationSize = 10)
private Long id;
private String title;
//Getters and setters omitted for brevity
}
@vlad_mihalcea vladmihalcea.com
Identifier portability – XML mapping
<?xml version="1.0" encoding="UTF-8"?>
<entity-mappings
xmlns="http://xmlns.jcp.org/xml/ns/persistence/orm"
xmlns:xsi=http://www.w3.org/2001/XMLSchema-instance
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence/orm_2_2.xsd"
version="2.2">
<package>com.vladmihalcea.book.hpjp.hibernate.identifier.global</package>
<entity class="Post" access="FIELD">
<attributes>
<id name="id">
<generated-value strategy="IDENTITY"/>
</id>
</attributes>
</entity>
</entity-mappings
@vlad_mihalcea vladmihalcea.com
Custom types – IP address column
• IP address stored in the Classless Inter-Domain Routing format
• VARCHAR(18)
• BIGINT column encoding – 4 bytes (e.g. 192.168.123.231) + 1 byte (e.g. 24)
• PostgreSQL cidr or inet type (requires 7 bytes)
@vlad_mihalcea vladmihalcea.com
Custom types – PostgreSQL inet column
Event matchingEvent = (Event) entityManager
.createNativeQuery(
"SELECT e.* " +
"FROM event e " +
"WHERE " +
" e.ip && CAST(:network AS inet) = TRUE")
.setParameter("network", "192.168.0.1/24")
.getSingleResult();
assertEquals("192.168.0.123", matchingEvent.getIp().getAddress());
@vlad_mihalcea vladmihalcea.com
Custom types – PostgreSQL inet column
@Entity(name = "Event")
@Table(name = "event")
@TypeDef(typeClass = IPv4Type.class, defaultForType = IPv4.class)
public class Event {
@Id
@GeneratedValue
private Long id;
@Column(name = "ip", columnDefinition = "inet")
private IPv4 ip;
//Getters and setters omitted for brevity
}
@vlad_mihalcea vladmihalcea.com
The hibernate-types project
<dependency>
<groupId>com.vladmihalcea</groupId>
<artifactId>hibernate-types-52</artifactId>
<version>${hibernate-types.version}</version>
</dependency>
<dependency>
<groupId>com.vladmihalcea</groupId>
<artifactId>hibernate-types-5</artifactId>
<version>${hibernate-types.version}</version>
</dependency>
@vlad_mihalcea vladmihalcea.com
JSON for unstructured data
@Entity(name = "Book")
@Table(name = "book")
@TypeDef(typeClass = JsonNodeBinaryType.class, defaultForType = JsonNode.class)
public class Book {
@Id
@GeneratedValue
private Long id;
@NaturalId
private String isbn;
@Column(columnDefinition = "jsonb")
private JsonNode properties;
//Getters and setters omitted for brevity
}
@vlad_mihalcea vladmihalcea.com
JSON for unstructured data
Book book = new Book();
book.setIsbn("978-9730228236");
book.setProperties(
JacksonUtil.toJsonNode(
"{" +
" "title": "High-Performance Java Persistence"," +
" "author": "Vlad Mihalcea"," +
" "publisher": "Amazon"," +
" "price": 44.99" +
"}"
)
);
@vlad_mihalcea vladmihalcea.com
JSON for unstructured data
Book book = entityManager.unwrap(Session.class).bySimpleNaturalId(Book.class)
.load("978-9730228236");
book.setProperties(
JacksonUtil.toJsonNode(
"{" +
" "title": "High-Performance Java Persistence"," +
" "author": "Vlad Mihalcea"," +
" "publisher": "Amazon"," +
" "price": 44.99," +
" "url": "https://www.amzn.com/973022823X/"" +
"}"
)
);
@vlad_mihalcea vladmihalcea.com
Statement caching
CC BY 2.0 - https://www.flickr.com/photos/southbeachcars/16065861514/
@vlad_mihalcea vladmihalcea.com
Execution plan cache
@vlad_mihalcea vladmihalcea.com
Oracle server-side statement caching
• Soft parse
• Hard parse
• Bind peeking
• Adaptive cursor sharing (since 11g)
@vlad_mihalcea vladmihalcea.com
SQL Server server-side statement caching
• Execution plan cache
• Parameter sniffing
• Prepared statements should use the qualified object name
SELECT *
FROM etl.dbo.task
WHERE status = ?
@vlad_mihalcea vladmihalcea.com
PostgreSQL server-side statement caching
• Prior to 9.2 – execution plan cache
• 9.2 – deferred optimization
• The prepareThreshold connection property
@vlad_mihalcea vladmihalcea.com
MySQL server-side statement caching
• No execution plan cache
• Since Connector/J 5.0.5 PreparedStatements are emulated
• To activate server-side prepared statements:
• useServerPrepStmts
• cachePrepStmts
@vlad_mihalcea vladmihalcea.com
Client-side statement caching
• Recycling Statement, PreparedStatement or
CallableStatement objects
• Reusing database cursors
@vlad_mihalcea vladmihalcea.com
Oracle implicit client-side statement caching
• Connection-level cache
• PreparedStatement and CallabledStatement only
• Caches metadata only
connectionProperties.put(
"oracle.jdbc.implicitStatementCacheSize",
Integer.toString(cacheSize));
dataSource.setConnectionProperties(connectionProperties);
@vlad_mihalcea vladmihalcea.com
Oracle implicit client-side statement caching
• Once enabled, all statements are cached.
• Can be disabled on a per statement basis
if (statement.isPoolable()) {
statement.setPoolable(false);
}
@vlad_mihalcea vladmihalcea.com
Oracle explicit client-side statement caching
• Caches both metadata, execution state and data
OracleConnection oracleConnection =
(OracleConnection) connection;
oracleConnection.setExplicitCachingEnabled(true);
oracleConnection.setStatementCacheSize(cacheSize);
@vlad_mihalcea vladmihalcea.com
Oracle explicit client-side statement caching
PreparedStatement statement = oracleConnection.
getStatementWithKey(SELECT_POST_KEY);
if (statement == null) {
statement = connection.prepareStatement(SELECT_POST);
}
try {
statement.setInt(1, 10);
statement.execute();
} finally {
((OraclePreparedStatement) statement).closeWithKey(SELECT_POST_KEY);
}
@vlad_mihalcea vladmihalcea.com
SQL Server client-side statement caching
• The SQL Server JDBC driver version 6.3 added support for statement
caching.
• Prepared Statement caching is disabled by default.
connection.setStatementPoolingCacheSize(10);
connection.setDisableStatementPooling(false);
@vlad_mihalcea vladmihalcea.com
PostgreSQL Server client-side statement caching
• PostgreSQL JDBC Driver 9.4-1202 makes client-side statement
connection-bound instead of statement-bound
• Configurable:
• preparedStatementCacheQueries (default is 256)
• preparedStatementCacheSizeMiB (default is 5MB)
• Statement.setPoolable(false) is not supported
@vlad_mihalcea vladmihalcea.com
MySQL Server client-side statement caching
• Configurable:
• cachePrepStmts (default is false)
Required for server-side statement caching as well
• prepStmtCacheSize (default is 25)
• prepStmtCacheSqlLimit (default is 256)
• Statement.setPoolable(false) works for server-side
statements only
@vlad_mihalcea vladmihalcea.com
Statement caching gain (one minute interval)
Database System No Caching Throughput
(SPM)
Caching Throughput
(SPM)
Percentage Gain
DB_A 419 833 507 286 20.83%
DB_B 194 837 303 100 55.56%
DB_C 116 708 166 443 42.61%
DB_D 15 522 15 550 0.18%
@vlad_mihalcea vladmihalcea.com
Queries
CC BY 2.0 - https://www.flickr.com/photos/justinbaeder/5317820857/
@vlad_mihalcea vladmihalcea.com
Criteria API literal handling
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<Book> cq = cb.createQuery(Book.class);
Root<Book> root = cq.from(Book.class);
cq.select(root);
cq.where(cb.equal(root.get("name"), "High-Performance Java Persistence"));
Book book = entityManager.createQuery(cq).getSingleResult();
SELECT
b.id AS id1_0_, b.isbn AS isbn2_0_, b.name AS name3_0_
FROM
book b
WHERE
b.name = ?
@vlad_mihalcea vladmihalcea.com
Criteria API literal handling
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<Book> cq = cb.createQuery(Book.class);
Root<Book> root = cq.from(Book.class);
cq.select(root);
cq.where(cb.equal(root.get("isbn"), 978_9730228236L));
Book book = entityManager.createQuery(cq).getSingleResult();
SELECT
b.id AS id1_0_, b.isbn AS isbn2_0_, b.name AS name3_0_
FROM
book b
WHERE
b.isbn = 9789730228236
@vlad_mihalcea vladmihalcea.com
Criteria API literal handling
@vlad_mihalcea vladmihalcea.com
Criteria API literal handling
<property
name="hibernate.criteria.literal_handling_mode"
value="bind"
/>
<property
name="hibernate.criteria.literal_handling_mode"
value="inline"
/>
<property
name="hibernate.criteria.literal_handling_mode"
value="auto"
/>
@vlad_mihalcea vladmihalcea.com
IN query padding optimization
List<Post> getPostByIds(EntityManager entityManager, Integer... ids) {
return entityManager.createQuery(
"select p " +
"from Post p " +
"where p.id in :ids", Post.class)
.setParameter("ids", Arrays.asList(ids))
.getResultList();
}
@vlad_mihalcea vladmihalcea.com
IN query padding optimization
SELECT p.id AS id1_0_, p.title AS title2_0_
FROM post p
WHERE p.id IN (?, ?, ?)
SELECT p.id AS id1_0_, p.title AS title2_0_
FROM post p
WHERE p.id IN (?, ?, ?, ?)
assertEquals(3, getPostByIds(entityManager, 1, 2, 3).size());
assertEquals(4, getPostByIds(entityManager, 1, 2, 3, 4).size());
@vlad_mihalcea vladmihalcea.com
IN query padding optimization
SELECT p.id AS id1_0_, p.title AS title2_0_
FROM post p
WHERE p.id IN (?, ?, ?, ?, ?)
SELECT p.id AS id1_0_, p.title AS title2_0_
FROM post p
WHERE p.id IN (?, ?, ?, ?, ?, ?)
assertEquals(5, getPostByIds(entityManager, 1, 2, 3, 4, 5).size());
assertEquals(6, getPostByIds(entityManager, 1, 2, 3, 4, 5, 6).size());
@vlad_mihalcea vladmihalcea.com
IN query padding optimization
@vlad_mihalcea vladmihalcea.com
IN query padding optimization
<property name="hibernate.query.in_clause_parameter_padding" value="true" />
SELECT p.id AS id1_0_, p.title AS title2_0_
FROM post p
WHERE p.id IN (?, ?, ?, ?) -- Params: (1, 2, 3, 3)
SELECT p.id AS id1_0_, p.title AS title2_0_
FROM post p
WHERE p.id IN (?, ?, ?, ?) -- Params: (1, 2, 3, 4)
assertEquals(3, getPostByIds(entityManager, 1, 2, 3).size());
assertEquals(4, getPostByIds(entityManager, 1, 2, 3, 4).size());
@vlad_mihalcea vladmihalcea.com
IN query padding optimization
assertEquals(5, getPostByIds(entityManager, 1, 2, 3, 4, 5).size());
SELECT p.id AS id1_0_, p.title AS title2_0_
FROM post p
WHERE p.id IN (?, ?, ?, ?, ?, ?, ?, ?) -- Params: (1, 2, 3, 4, 5, 5, 5, 5)
assertEquals(6, getPostByIds(entityManager, 1, 2, 3, 4, 5, 6).size());
SELECT p.id AS id1_0_, p.title AS title2_0_
FROM post p
WHERE p.id IN (?, ?, ?, ?, ?, ?, ?, ?) -- Params: (1, 2, 3, 4, 5, 6, 6, 6)
@vlad_mihalcea vladmihalcea.com
Query plan cache
• Entity queries (JPQL, Criteria API) need to be compiled to SQL
• Configurable:
• hibernate.query.plan_cache_max_size (2048)
• hibernate.query.plan_parameter_metadata_max_size (128)
@vlad_mihalcea vladmihalcea.com
Entity query plan cache improvement
@vlad_mihalcea vladmihalcea.com
Native SQL query plan cache improvement
@vlad_mihalcea vladmihalcea.com
JPQL DISTINCT scalar query
List<Integer> publicationYears = entityManager.createQuery(
"select distinct year(p.createdOn) " +
"from Post p " +
"order by year(p.createdOn)", Integer.class)
.getResultList();
SELECT DISTINCT
extract(YEAR FROM p.created_on) AS col_0_0_
FROM post p
ORDER BY (YEAR FROM p.created_on)
@vlad_mihalcea vladmihalcea.com
JPQL DISTINCT entity query
List<Post> posts = entityManager.createQuery(
"select distinct p " +
"from Post p " +
"left join fetch p.comments " +
"where p.title = :title", Post.class)
.setParameter("title", "High-Performance Java Persistence")
.getResultList();
SELECT DISTINCT
p.id AS id1_0_0_, pc.id AS id1_1_1_, p.title AS title2_0_0_,
pc.review AS review2_1_1_, pc.post_id AS post_id3_1_0__,
pc.id AS id1_1_0__
FROM post p
LEFT OUTER JOIN post_comment pc ON p.id=pc.post_id
WHERE p.title = ?
@vlad_mihalcea vladmihalcea.com
JPQL DISTINCT entity query
@vlad_mihalcea vladmihalcea.com
JPQL DISTINCT entity query
List<Post> posts = entityManager.createQuery(
"select distinct p " +
"from Post p " +
"left join fetch p.comments " +
"where p.title = :title", Post.class)
.setParameter("title", "High-Performance Java Persistence")
.setHint(QueryHints.HINT_PASS_DISTINCT_THROUGH, false)
.getResultList();
SELECT
p.id AS id1_0_0_, pc.id AS id1_1_1_, p.title AS title2_0_0_,
pc.review AS review2_1_1_, pc.post_id AS post_id3_1_0__,
pc.id AS id1_1_0__
FROM post p
LEFT OUTER JOIN post_comment pc ON p.id=pc.post_id
WHERE p.title = ?
@vlad_mihalcea vladmihalcea.com
JPQL DISTINCT entity query
@vlad_mihalcea vladmihalcea.com
Fetching
CC BY 2.0 - https://www.flickr.com/photos/bala_/3544603505/
@vlad_mihalcea vladmihalcea.com
Persistence Context – loaded state
@vlad_mihalcea vladmihalcea.com
Persistence Context – dirty checking
@vlad_mihalcea vladmihalcea.com
Persistence Context size
//session-level configuration
Session session = entityManager.unwrap(Session.class);
session.setDefaultReadOnly(true);
//query-level configuration
List<Post> posts = entityManager.createQuery(
"select p from Post p", Post.class)
.setHint(QueryHints.HINT_READONLY, true)
.getResultList();
@vlad_mihalcea vladmihalcea.com
@Transactional(readOnly = true)
public List<Post> findAllByTitle(String title) {
List<Post> posts = postDAO.findByTitle(title);
org.hibernate.engine.spi.PersistenceContext persistenceContext =
getHibernatePersistenceContext();
for(Post post : posts) {
assertTrue(entityManager.contains(post));
EntityEntry entityEntry = persistenceContext.getEntry(post);
assertNull(entityEntry.getLoadedState());
}
return posts;
}
Spring 5.1 read-only optimization
@vlad_mihalcea vladmihalcea.com
Fetching – Pagination
• JPA / Hibernate API works for both entity and native SQL queries
List<PostCommentSummary> summaries =
entityManager.createQuery(
"select new PostCommentSummary( " +
" p.id, p.title, c.review ) " +
"from PostComment c " +
"join c.post p")
.setFirstResult(pageStart)
.setMaxResults(pageSize)
.getResultList();
@vlad_mihalcea vladmihalcea.com
Fetching – 100k vs 100 rows
Fetch all Fetch limit
0
500
1000
1500
2000
2500
3000
3500
4000
4500
5000
Time(ms)
DB_A DB_B DB_C DB_D
@vlad_mihalcea vladmihalcea.com
JPA 2.2 Streaming
@vlad_mihalcea vladmihalcea.com
JPA 2.2 Streaming
default Stream getResultStream() {
return getResultList().stream();
}
final ScrollableResultsImplementor scrollableResults = scroll(
ScrollMode.FORWARD_ONLY
);
@vlad_mihalcea vladmihalcea.com
JDBC-level streaming support
• You still need to consider the Statement.setFetchSize.
• On MySQL, you need to set it to Integer.MIN_VALUE.
• On PostgreSQL, you need to set it to a positive integer value.
• What about the Execution Plan?
@vlad_mihalcea vladmihalcea.com
JPA 2.2 Streaming – Execution Plans
List<String> executionPlanLines = doInJPA(entityManager -> {
try(Stream<String> postStream = entityManager
.createNativeQuery(
"EXPLAIN ANALYZE " +
"SELECT p " +
"FROM post p " +
"ORDER BY p.created_on DESC")
.setHint(QueryHints.HINT_FETCH_SIZE, 50)
.getResultStream()
) {
return postStream.limit(50).collect(Collectors.toList());
}
});
CREATE INDEX idx_post_created_on ON post (created_on DESC)
@vlad_mihalcea vladmihalcea.com
JPA 2.2 Streaming – Execution Plans
LOGGER.info( "Execution plan: {}",
executionPlanLines
.stream()
.collect(Collectors.joining( "n" ))
);
Execution plan:
Sort (cost=65.53..66.83 rows=518 width=564)
(actual time=2.876..3.399 rows=5000 loops=1)
Sort Key: created_on DESC
Sort Method: quicksort Memory: 896kB
-> Seq Scan on post p
(cost=0.00..42.18 rows=518 width=564)
(actual time=0.050..1.371 rows=5000 loops=1)
Planning time: 1.586 ms
Execution time: 4.061 ms
@vlad_mihalcea vladmihalcea.com
JPA 2.2 Streaming – Execution Plans
List<String> executionPlanLines = doInJPA(entityManager -> {
return entityManager
.createNativeQuery(
"EXPLAIN ANALYZE " +
"SELECT p " +
"FROM post p " +
"ORDER BY p.created_on DESC")
.setMaxResults(50)
.getResultList();
});
LOGGER.info("Execution plan: {}",
executionPlanLines
.stream()
.collect(Collectors.joining("n"))
);
@vlad_mihalcea vladmihalcea.com
JPA 2.2 Streaming – Execution Plans
Execution plan:
Limit (cost=0.28..25.35 rows=50 width=564)
(actual time=0.038..0.051 rows=50 loops=1)
-> Index Scan using idx_post_created_on on post p
(cost=0.28..260.04 rows=518 width=564)
(actual time=0.037..0.049 rows=50 loops=1)
Planning time: 1.511 ms
Execution time: 0.148 ms
@vlad_mihalcea vladmihalcea.com
Fetching – Open Session in View Anti-Pattern
@vlad_mihalcea vladmihalcea.com
Fetching – Open Session in View Anti-Pattern
@vlad_mihalcea vladmihalcea.com
Fetching – Temporary Session Anti-Pattern
• “Band aid” for LazyInitializationException
• One temporary Session/Connection for every lazily fetched
association
<property
name="hibernate.enable_lazy_load_no_trans"
value="true"/>
@vlad_mihalcea vladmihalcea.com
Batching
CC BY-SA 2.0 - https://www.flickr.com/photos/dozodomo/6975654335/
@vlad_mihalcea vladmihalcea.com
JDBC Batch Updates
@vlad_mihalcea vladmihalcea.com
Transactional write-behind cache
@vlad_mihalcea vladmihalcea.com
Action queue
@vlad_mihalcea vladmihalcea.com
Batch processing – flush-clear-commit
try {
entityManager.getTransaction().begin();
for ( int i = 0; i < entityCount; ++i ) {
if ( i > 0 && i % batchSize == 0 ) {
flush( entityManager );
}
entityManager.persist( new Post( String.format( "Post %d", i + 1 ) ) );
}
entityManager.getTransaction().commit();
} catch (RuntimeException e) {
if ( entityManager.getTransaction().isActive()) {
entityManager.getTransaction().rollback();
}
throw e;
} finally {
entityManager.close();
}
@vlad_mihalcea vladmihalcea.com
private void flush(EntityManager entityManager) {
entityManager.flush();
entityManager.clear();
entityManager.getTransaction().commit();
entityManager.getTransaction().begin();
}
Batch processing – flush and commit
@vlad_mihalcea vladmihalcea.com
Hibernate batching – default behavior
for (int i = 0; i < 3; i++) {
entityManager.persist(
new Post(String.format("Post no. %d", i + 1))
);
}
INSERT INTO post (title, id) VALUES ('Post no. 1', 1)
INSERT INTO post (title, id) VALUES ('Post no. 2', 2)
INSERT INTO post (title, id) VALUES ('Post no. 3', 3)
@vlad_mihalcea vladmihalcea.com
Enable JDBC batching
<property name="hibernate.jdbc.batch_size" value="5"/>
Query: ["INSERT INTO post (title, id) VALUES (?, ?)"],
Params: [('Post no. 1', 1),
('Post no. 2', 2),
('Post no. 3', 3)]
entityManager.unwrap(Session.class).setJdbcBatchSize(10);
for (long i = 0; i < 10; ++i) {
Post post = new Post();
post.setTitle(String.format("Post nr %d", i));
entityManager.persist(post);
}
@vlad_mihalcea vladmihalcea.com
PostgreSQL batch statements
log_statement = 'all'
LOG: execute S_2: insert into post (title, id) values ($1, $2)
DETAIL: parameters: $1 = 'Post no. 1', $2 = '1'
LOG: execute S_2: insert into post (title, id) values ($1, $2)
DETAIL: parameters: $1 = 'Post no. 2', $2 = '2'
LOG: execute S_2: insert into post (title, id) values ($1, $2)
DETAIL: parameters: $1 = 'Post no. 3', $2 = '3'
@vlad_mihalcea vladmihalcea.com
PostgreSQL rewrite batch statements
PGSimpleDataSource dataSource = (PGSimpleDataSource) dataSource();
dataSource.setReWriteBatchedInserts(true);
LOG: execute <unnamed>: insert into post (title, id)
values ($1, $2),($3, $4),($5, $6)
DETAIL: parameters: $1 = 'Post no. 1', $2 = '1’,
$3 = 'Post no. 2', $4 = '2’,
$5 = 'Post no. 3', $6 = '3'
@vlad_mihalcea vladmihalcea.com
Default UPDATE - Post entity mapping
@Entity(name = "Post")
@Table(name = "post")
public class Post {
@Id
private Long id;
private String title;
private long likes;
//Getters and setters omitted for brevity
}
@vlad_mihalcea vladmihalcea.com
Default UPDATE - Post entity data
Post post1 = new Post();
post1.setId(1L);
post1.setTitle("High-Performance Java Persistence");
entityManager.persist(post1);
Post post2 = new Post();
post2.setId(2L);
post2.setTitle("Java Persistence with Hibernate");
entityManager.persist(post2);
@vlad_mihalcea vladmihalcea.com
Default UPDATE - statement batching
Post post1 = entityManager.find(Post.class, 1L);
post1.setTitle("High-Performance Java Persistence 2nd Edition");
Post post2 = entityManager.find(Post.class, 2L);
post2.setLikes(12);
entityManager.flush();
Query :[
"update post set likes=?, title=? where id=?"
],
Params:[
(0, High-Performance Java Persistence 2nd Edition, 1),
(12, Java Persistence with Hibernate, 2)
]
@vlad_mihalcea vladmihalcea.com
Default UPDATE disadvantages
• Column size
• Indexes
• Replication
• Undo and redo log
• Triggers
@vlad_mihalcea vladmihalcea.com
Hibernate dynamic update
@Entity(name = "Post")
@Table(name = "post")
@DynamicUpdate
public class Post {
@Id
private Long id;
private String title;
private long likes;
//Getters and setters omitted for brevity
}
@vlad_mihalcea vladmihalcea.com
Hibernate dynamic update
Query:["update post set title=? where id=?"],
Params:[(High-Performance Java Persistence 2nd Edition, 1)]
Query:["update post set likes=? where id=?"],
Params:[(12, 2)]
Post post1 = entityManager.find(Post.class, 1L);
post1.setTitle("High-Performance Java Persistence 2nd Edition");
Post post2 = entityManager.find(Post.class, 2L);
post2.setlikes(12);
entityManager.flush();
@vlad_mihalcea vladmihalcea.com
Updating detached entities - Post and PostComment
List<Post> posts = doInJPA(entityManager -> {
return entityManager.createQuery(
"select p " +
"from Post p " +
"join fetch p.comments ", Post.class)
.getResultList();
});
for (Post post: posts) {
post.setTitle("Vlad Mihalcea's " + post.getTitle());
for (PostComment comment: post.getComments()) {
comment.setReview(comment.getReview() + " read!");
}
}
@vlad_mihalcea vladmihalcea.com
• JPA merge
• Hibernate update
JPA merge and Hibernate update
for (Post post: posts) {
entityManager.merge(post);
}
Session session = entityManager.unwrap(Session.class);
for (Post post: posts) {
session.update(post);
}
@vlad_mihalcea vladmihalcea.com
JPA merge – SELECT statements
SELECT p.id AS id1_0_1_, p.title AS title2_0_1_, c.post_id AS post_id3_1_3_,
c.id AS id1_1_3_, c.review AS review2_1_0_
FROM post p
LEFT OUTER JOIN post_comment c ON p.id = c.post_id
WHERE p.id = 1
SELECT p.id AS id1_0_1_, p.title AS title2_0_1_, c.post_id AS post_id3_1_3_,
c.id AS id1_1_3_, c.review AS review2_1_0_
FROM post p
LEFT OUTER JOIN post_comment c ON p.id = c.post_id
WHERE p.id = 3
SELECT p.id AS id1_0_1_, p.title AS title2_0_1_, c.post_id AS post_id3_1_3_,
c.id AS id1_1_3_, c.review AS review2_1_0_
FROM post p
LEFT OUTER JOIN post_comment c ON p.id = c.post_id
WHERE p.id = 5
…
@vlad_mihalcea vladmihalcea.com
JPA merge – UPDATE statements
Query:[
"update post set title=? where id=?"
],
Params:[
(Vlad Mihalcea's High-Performance Java Persistence, Part no. 0, 1),
(Vlad Mihalcea's High-Performance Java Persistence, Part no. 1, 3),
(Vlad Mihalcea's High-Performance Java Persistence, Part no. 2, 5)
]
Query:[
"update post_comment set post_id=?, review=? where id=?"
],
Params:[
(1, Excellent read!, 2),
(3, Excellent read!, 4),
(5, Excellent read!, 6)
]
@vlad_mihalcea vladmihalcea.com
Hibernate-specific update operation
Query:[
"update post set title=? where id=?"
],
Params:[
(Vlad Mihalcea's High-Performance Java Persistence, Part no. 0, 1),
(Vlad Mihalcea's High-Performance Java Persistence, Part no. 1, 3),
(Vlad Mihalcea's High-Performance Java Persistence, Part no. 2, 5)
]
Query:[
"update post_comment set post_id=?, review=? where id=?"
],
Params:[
(1, Excellent read!, 2),
(3, Excellent read!, 4),
(5, Excellent read!, 6)
]
@vlad_mihalcea vladmihalcea.com
Connections
CC BY 2.0 - https://www.flickr.com/photos/justinbaeder/5317820857/
@vlad_mihalcea vladmihalcea.com
Resource-local connection acquisition
@vlad_mihalcea vladmihalcea.com
Immediate connection acquisition
@PersistenceContext
private EntityManager entityManager;
@Transactional
public void importForecasts(String dataFilePath) {
Document forecastXmlDocument = readXmlDocument( dataFilePath );
List<Forecast> forecasts = parseForecasts(forecastXmlDocument);
for(Forecast forecast : forecasts) {
entityManager.persist( forecast );
}
}
@vlad_mihalcea vladmihalcea.com
Resource-local delay connection acquisition
<property
name="hibernate.connection.provider_disables_autocommit"
value="true"
/>
HikariConfig hikariConfig = new HikariConfig();
hikariConfig.setDataSourceClassName(dataSourceClassName);
hikariConfig.setDataSourceProperties(dataSourceProperties);
hikariConfig.setMinimumPoolSize(minPoolSize);
hikariConfig.setMaximumPoolSize(maxPoolSize);
hikariConfig.setAutoCommit(false);
DataSource datasource = new HikariDataSource(hikariConfig);
@vlad_mihalcea vladmihalcea.com
Resource-local connection acquisition optimization
@vlad_mihalcea vladmihalcea.com
Thank you
• Twitter: @vlad_mihalcea
• Blog: https://vladmihalcea.com
• Courses: https://vladmihalcea.com/courses
• Book: https://vladmihalcea.com/books/high-performance-java-persistence/
Ad

More Related Content

What's hot (20)

Mikhail Egorov - Hunting for bugs in Adobe Experience Manager webapps
Mikhail Egorov - Hunting for bugs in Adobe Experience Manager webappsMikhail Egorov - Hunting for bugs in Adobe Experience Manager webapps
Mikhail Egorov - Hunting for bugs in Adobe Experience Manager webapps
hacktivity
 
Asynchronous JavaScript Programming with Callbacks & Promises
Asynchronous JavaScript Programming with Callbacks & PromisesAsynchronous JavaScript Programming with Callbacks & Promises
Asynchronous JavaScript Programming with Callbacks & Promises
Hùng Nguyễn Huy
 
Java 9 Features
Java 9 FeaturesJava 9 Features
Java 9 Features
NexThoughts Technologies
 
Express node js
Express node jsExpress node js
Express node js
Yashprit Singh
 
Intro to Asynchronous Javascript
Intro to Asynchronous JavascriptIntro to Asynchronous Javascript
Intro to Asynchronous Javascript
Garrett Welson
 
Testando API REST - Parte 1
Testando API REST - Parte 1Testando API REST - Parte 1
Testando API REST - Parte 1
alinebiath
 
Packages in java
Packages in javaPackages in java
Packages in java
jamunaashok
 
Callback Function
Callback FunctionCallback Function
Callback Function
Roland San Nicolas
 
Node.js Express Tutorial | Node.js Tutorial For Beginners | Node.js + Expres...
Node.js Express Tutorial | Node.js Tutorial For Beginners | Node.js +  Expres...Node.js Express Tutorial | Node.js Tutorial For Beginners | Node.js +  Expres...
Node.js Express Tutorial | Node.js Tutorial For Beginners | Node.js + Expres...
Edureka!
 
Node.js Tutorial for Beginners | Node.js Web Application Tutorial | Node.js T...
Node.js Tutorial for Beginners | Node.js Web Application Tutorial | Node.js T...Node.js Tutorial for Beginners | Node.js Web Application Tutorial | Node.js T...
Node.js Tutorial for Beginners | Node.js Web Application Tutorial | Node.js T...
Edureka!
 
Introduction to java 8 stream api
Introduction to java 8 stream apiIntroduction to java 8 stream api
Introduction to java 8 stream api
Vladislav sidlyarevich
 
Core Java
Core JavaCore Java
Core Java
Priyanka Pradhan
 
ZIO-Direct - Functional Scala 2022
ZIO-Direct - Functional Scala 2022ZIO-Direct - Functional Scala 2022
ZIO-Direct - Functional Scala 2022
Alexander Ioffe
 
Keycloak theme customization
Keycloak theme customizationKeycloak theme customization
Keycloak theme customization
Ravi Yasas
 
Wildcard In database
Wildcard In databaseWildcard In database
Wildcard In database
jamilmalik19
 
Arrays in php
Arrays in phpArrays in php
Arrays in php
Laiby Thomas
 
L21 io streams
L21 io streamsL21 io streams
L21 io streams
teach4uin
 
8. sql
8. sql8. sql
8. sql
khoahuy82
 
Mastering Async/Await in JavaScript
Mastering Async/Await in JavaScriptMastering Async/Await in JavaScript
Mastering Async/Await in JavaScript
Valeri Karpov
 
Super Keyword in Java.pptx
Super Keyword in Java.pptxSuper Keyword in Java.pptx
Super Keyword in Java.pptx
KrutikaWankhade1
 
Mikhail Egorov - Hunting for bugs in Adobe Experience Manager webapps
Mikhail Egorov - Hunting for bugs in Adobe Experience Manager webappsMikhail Egorov - Hunting for bugs in Adobe Experience Manager webapps
Mikhail Egorov - Hunting for bugs in Adobe Experience Manager webapps
hacktivity
 
Asynchronous JavaScript Programming with Callbacks & Promises
Asynchronous JavaScript Programming with Callbacks & PromisesAsynchronous JavaScript Programming with Callbacks & Promises
Asynchronous JavaScript Programming with Callbacks & Promises
Hùng Nguyễn Huy
 
Intro to Asynchronous Javascript
Intro to Asynchronous JavascriptIntro to Asynchronous Javascript
Intro to Asynchronous Javascript
Garrett Welson
 
Testando API REST - Parte 1
Testando API REST - Parte 1Testando API REST - Parte 1
Testando API REST - Parte 1
alinebiath
 
Packages in java
Packages in javaPackages in java
Packages in java
jamunaashok
 
Node.js Express Tutorial | Node.js Tutorial For Beginners | Node.js + Expres...
Node.js Express Tutorial | Node.js Tutorial For Beginners | Node.js +  Expres...Node.js Express Tutorial | Node.js Tutorial For Beginners | Node.js +  Expres...
Node.js Express Tutorial | Node.js Tutorial For Beginners | Node.js + Expres...
Edureka!
 
Node.js Tutorial for Beginners | Node.js Web Application Tutorial | Node.js T...
Node.js Tutorial for Beginners | Node.js Web Application Tutorial | Node.js T...Node.js Tutorial for Beginners | Node.js Web Application Tutorial | Node.js T...
Node.js Tutorial for Beginners | Node.js Web Application Tutorial | Node.js T...
Edureka!
 
ZIO-Direct - Functional Scala 2022
ZIO-Direct - Functional Scala 2022ZIO-Direct - Functional Scala 2022
ZIO-Direct - Functional Scala 2022
Alexander Ioffe
 
Keycloak theme customization
Keycloak theme customizationKeycloak theme customization
Keycloak theme customization
Ravi Yasas
 
Wildcard In database
Wildcard In databaseWildcard In database
Wildcard In database
jamilmalik19
 
L21 io streams
L21 io streamsL21 io streams
L21 io streams
teach4uin
 
Mastering Async/Await in JavaScript
Mastering Async/Await in JavaScriptMastering Async/Await in JavaScript
Mastering Async/Await in JavaScript
Valeri Karpov
 
Super Keyword in Java.pptx
Super Keyword in Java.pptxSuper Keyword in Java.pptx
Super Keyword in Java.pptx
KrutikaWankhade1
 

Similar to JPA and Hibernate Performance Tips (20)

Spring data requery
Spring data requerySpring data requery
Spring data requery
Sunghyouk Bae
 
Spring 3: What's New
Spring 3: What's NewSpring 3: What's New
Spring 3: What's New
Ted Pennings
 
Sqlapi0.1
Sqlapi0.1Sqlapi0.1
Sqlapi0.1
jitendral
 
Servlets 3.0 - Asynchronous, Extensibility, Ease-of-use @ JavaOne Brazil 2010
Servlets 3.0 - Asynchronous, Extensibility, Ease-of-use @ JavaOne Brazil 2010Servlets 3.0 - Asynchronous, Extensibility, Ease-of-use @ JavaOne Brazil 2010
Servlets 3.0 - Asynchronous, Extensibility, Ease-of-use @ JavaOne Brazil 2010
Arun Gupta
 
Jdbc[1]
Jdbc[1]Jdbc[1]
Jdbc[1]
Fulvio Corno
 
JDBC programming
JDBC programmingJDBC programming
JDBC programming
Fulvio Corno
 
Ppt on web development and this has all details
Ppt on web development and this has all detailsPpt on web development and this has all details
Ppt on web development and this has all details
gogijoshiajmer
 
Scala Frameworks for Web Application 2016
Scala Frameworks for Web Application 2016Scala Frameworks for Web Application 2016
Scala Frameworks for Web Application 2016
takezoe
 
Scala and Spring
Scala and SpringScala and Spring
Scala and Spring
Eberhard Wolff
 
Spring Day | Spring and Scala | Eberhard Wolff
Spring Day | Spring and Scala | Eberhard WolffSpring Day | Spring and Scala | Eberhard Wolff
Spring Day | Spring and Scala | Eberhard Wolff
JAX London
 
Integrating Wicket with Java EE 6
Integrating Wicket with Java EE 6Integrating Wicket with Java EE 6
Integrating Wicket with Java EE 6
Michael Plöd
 
Introduction to JDBC and database access in web applications
Introduction to JDBC and database access in web applicationsIntroduction to JDBC and database access in web applications
Introduction to JDBC and database access in web applications
Fulvio Corno
 
Multi Client Development with Spring
Multi Client Development with SpringMulti Client Development with Spring
Multi Client Development with Spring
Joshua Long
 
Advance java session 5
Advance java session 5Advance java session 5
Advance java session 5
Smita B Kumar
 
Backbone js
Backbone jsBackbone js
Backbone js
Rohan Chandane
 
Spring Framework Petclinic sample application
Spring Framework Petclinic sample applicationSpring Framework Petclinic sample application
Spring Framework Petclinic sample application
Antoine Rey
 
JavaOne India 2011 - Servlets 3.0
JavaOne India 2011 - Servlets 3.0JavaOne India 2011 - Servlets 3.0
JavaOne India 2011 - Servlets 3.0
Arun Gupta
 
Integrating SAP the Java EE Way - JBoss One Day talk 2012
Integrating SAP the Java EE Way - JBoss One Day talk 2012Integrating SAP the Java EE Way - JBoss One Day talk 2012
Integrating SAP the Java EE Way - JBoss One Day talk 2012
hwilming
 
Dropwizard
DropwizardDropwizard
Dropwizard
Scott Leberknight
 
Red Hat Agile integration Workshop Labs
Red Hat Agile integration Workshop LabsRed Hat Agile integration Workshop Labs
Red Hat Agile integration Workshop Labs
Judy Breedlove
 
Spring 3: What's New
Spring 3: What's NewSpring 3: What's New
Spring 3: What's New
Ted Pennings
 
Servlets 3.0 - Asynchronous, Extensibility, Ease-of-use @ JavaOne Brazil 2010
Servlets 3.0 - Asynchronous, Extensibility, Ease-of-use @ JavaOne Brazil 2010Servlets 3.0 - Asynchronous, Extensibility, Ease-of-use @ JavaOne Brazil 2010
Servlets 3.0 - Asynchronous, Extensibility, Ease-of-use @ JavaOne Brazil 2010
Arun Gupta
 
Ppt on web development and this has all details
Ppt on web development and this has all detailsPpt on web development and this has all details
Ppt on web development and this has all details
gogijoshiajmer
 
Scala Frameworks for Web Application 2016
Scala Frameworks for Web Application 2016Scala Frameworks for Web Application 2016
Scala Frameworks for Web Application 2016
takezoe
 
Spring Day | Spring and Scala | Eberhard Wolff
Spring Day | Spring and Scala | Eberhard WolffSpring Day | Spring and Scala | Eberhard Wolff
Spring Day | Spring and Scala | Eberhard Wolff
JAX London
 
Integrating Wicket with Java EE 6
Integrating Wicket with Java EE 6Integrating Wicket with Java EE 6
Integrating Wicket with Java EE 6
Michael Plöd
 
Introduction to JDBC and database access in web applications
Introduction to JDBC and database access in web applicationsIntroduction to JDBC and database access in web applications
Introduction to JDBC and database access in web applications
Fulvio Corno
 
Multi Client Development with Spring
Multi Client Development with SpringMulti Client Development with Spring
Multi Client Development with Spring
Joshua Long
 
Advance java session 5
Advance java session 5Advance java session 5
Advance java session 5
Smita B Kumar
 
Spring Framework Petclinic sample application
Spring Framework Petclinic sample applicationSpring Framework Petclinic sample application
Spring Framework Petclinic sample application
Antoine Rey
 
JavaOne India 2011 - Servlets 3.0
JavaOne India 2011 - Servlets 3.0JavaOne India 2011 - Servlets 3.0
JavaOne India 2011 - Servlets 3.0
Arun Gupta
 
Integrating SAP the Java EE Way - JBoss One Day talk 2012
Integrating SAP the Java EE Way - JBoss One Day talk 2012Integrating SAP the Java EE Way - JBoss One Day talk 2012
Integrating SAP the Java EE Way - JBoss One Day talk 2012
hwilming
 
Red Hat Agile integration Workshop Labs
Red Hat Agile integration Workshop LabsRed Hat Agile integration Workshop Labs
Red Hat Agile integration Workshop Labs
Judy Breedlove
 
Ad

More from Vlad Mihalcea (7)

Awesome SQL Tips and Tricks - Voxxed Days Cluj - 2019
 Awesome SQL Tips and Tricks - Voxxed Days Cluj - 2019 Awesome SQL Tips and Tricks - Voxxed Days Cluj - 2019
Awesome SQL Tips and Tricks - Voxxed Days Cluj - 2019
Vlad Mihalcea
 
Transactions and Concurrency Control Patterns - 2019
Transactions and Concurrency Control Patterns - 2019Transactions and Concurrency Control Patterns - 2019
Transactions and Concurrency Control Patterns - 2019
Vlad Mihalcea
 
High-Performance Hibernate - JDK.io 2018
High-Performance Hibernate - JDK.io 2018High-Performance Hibernate - JDK.io 2018
High-Performance Hibernate - JDK.io 2018
Vlad Mihalcea
 
Transactions and Concurrency Control Patterns
Transactions and Concurrency Control PatternsTransactions and Concurrency Control Patterns
Transactions and Concurrency Control Patterns
Vlad Mihalcea
 
High Performance Hibernate JavaZone 2016
High Performance Hibernate JavaZone 2016High Performance Hibernate JavaZone 2016
High Performance Hibernate JavaZone 2016
Vlad Mihalcea
 
High-Performance Hibernate Devoxx France 2016
High-Performance Hibernate Devoxx France 2016High-Performance Hibernate Devoxx France 2016
High-Performance Hibernate Devoxx France 2016
Vlad Mihalcea
 
High-Performance JDBC Voxxed Bucharest 2016
High-Performance JDBC Voxxed Bucharest 2016High-Performance JDBC Voxxed Bucharest 2016
High-Performance JDBC Voxxed Bucharest 2016
Vlad Mihalcea
 
Awesome SQL Tips and Tricks - Voxxed Days Cluj - 2019
 Awesome SQL Tips and Tricks - Voxxed Days Cluj - 2019 Awesome SQL Tips and Tricks - Voxxed Days Cluj - 2019
Awesome SQL Tips and Tricks - Voxxed Days Cluj - 2019
Vlad Mihalcea
 
Transactions and Concurrency Control Patterns - 2019
Transactions and Concurrency Control Patterns - 2019Transactions and Concurrency Control Patterns - 2019
Transactions and Concurrency Control Patterns - 2019
Vlad Mihalcea
 
High-Performance Hibernate - JDK.io 2018
High-Performance Hibernate - JDK.io 2018High-Performance Hibernate - JDK.io 2018
High-Performance Hibernate - JDK.io 2018
Vlad Mihalcea
 
Transactions and Concurrency Control Patterns
Transactions and Concurrency Control PatternsTransactions and Concurrency Control Patterns
Transactions and Concurrency Control Patterns
Vlad Mihalcea
 
High Performance Hibernate JavaZone 2016
High Performance Hibernate JavaZone 2016High Performance Hibernate JavaZone 2016
High Performance Hibernate JavaZone 2016
Vlad Mihalcea
 
High-Performance Hibernate Devoxx France 2016
High-Performance Hibernate Devoxx France 2016High-Performance Hibernate Devoxx France 2016
High-Performance Hibernate Devoxx France 2016
Vlad Mihalcea
 
High-Performance JDBC Voxxed Bucharest 2016
High-Performance JDBC Voxxed Bucharest 2016High-Performance JDBC Voxxed Bucharest 2016
High-Performance JDBC Voxxed Bucharest 2016
Vlad Mihalcea
 
Ad

Recently uploaded (20)

Best HR and Payroll Software in Bangladesh - accordHRM
Best HR and Payroll Software in Bangladesh - accordHRMBest HR and Payroll Software in Bangladesh - accordHRM
Best HR and Payroll Software in Bangladesh - accordHRM
accordHRM
 
S3 + AWS Athena how to integrate s3 aws plus athena
S3 + AWS Athena how to integrate s3 aws plus athenaS3 + AWS Athena how to integrate s3 aws plus athena
S3 + AWS Athena how to integrate s3 aws plus athena
aianand98
 
AI Agents with Gemini 2.0 - Beyond the Chatbot
AI Agents with Gemini 2.0 - Beyond the ChatbotAI Agents with Gemini 2.0 - Beyond the Chatbot
AI Agents with Gemini 2.0 - Beyond the Chatbot
Márton Kodok
 
Mobile Application Developer Dubai | Custom App Solutions by Ajath
Mobile Application Developer Dubai | Custom App Solutions by AjathMobile Application Developer Dubai | Custom App Solutions by Ajath
Mobile Application Developer Dubai | Custom App Solutions by Ajath
Ajath Infotech Technologies LLC
 
UI/UX Design & Development and Servicess
UI/UX Design & Development and ServicessUI/UX Design & Development and Servicess
UI/UX Design & Development and Servicess
marketing810348
 
Unit Two - Java Architecture and OOPS
Unit Two  -   Java Architecture and OOPSUnit Two  -   Java Architecture and OOPS
Unit Two - Java Architecture and OOPS
Nabin Dhakal
 
Albert Pintoy - A Distinguished Software Engineer
Albert Pintoy - A Distinguished Software EngineerAlbert Pintoy - A Distinguished Software Engineer
Albert Pintoy - A Distinguished Software Engineer
Albert Pintoy
 
Quasar Framework Introduction for C++ develpoers
Quasar Framework Introduction for C++ develpoersQuasar Framework Introduction for C++ develpoers
Quasar Framework Introduction for C++ develpoers
sadadkhah
 
wAIred_LearnWithOutAI_JCON_14052025.pptx
wAIred_LearnWithOutAI_JCON_14052025.pptxwAIred_LearnWithOutAI_JCON_14052025.pptx
wAIred_LearnWithOutAI_JCON_14052025.pptx
SimonedeGijt
 
Hydraulic Modeling And Simulation Software Solutions.pptx
Hydraulic Modeling And Simulation Software Solutions.pptxHydraulic Modeling And Simulation Software Solutions.pptx
Hydraulic Modeling And Simulation Software Solutions.pptx
julia smits
 
Troubleshooting JVM Outages – 3 Fortune 500 case studies
Troubleshooting JVM Outages – 3 Fortune 500 case studiesTroubleshooting JVM Outages – 3 Fortune 500 case studies
Troubleshooting JVM Outages – 3 Fortune 500 case studies
Tier1 app
 
Welcome to QA Summit 2025.
Welcome to QA Summit 2025.Welcome to QA Summit 2025.
Welcome to QA Summit 2025.
QA Summit
 
Aligning Projects to Strategy During Economic Uncertainty
Aligning Projects to Strategy During Economic UncertaintyAligning Projects to Strategy During Economic Uncertainty
Aligning Projects to Strategy During Economic Uncertainty
OnePlan Solutions
 
Medical Device Cybersecurity Threat & Risk Scoring
Medical Device Cybersecurity Threat & Risk ScoringMedical Device Cybersecurity Threat & Risk Scoring
Medical Device Cybersecurity Threat & Risk Scoring
ICS
 
Multi-Agent Era will Define the Future of Software
Multi-Agent Era will Define the Future of SoftwareMulti-Agent Era will Define the Future of Software
Multi-Agent Era will Define the Future of Software
Ivo Andreev
 
Buy vs. Build: Unlocking the right path for your training tech
Buy vs. Build: Unlocking the right path for your training techBuy vs. Build: Unlocking the right path for your training tech
Buy vs. Build: Unlocking the right path for your training tech
Rustici Software
 
Wilcom Embroidery Studio Crack Free Latest 2025
Wilcom Embroidery Studio Crack Free Latest 2025Wilcom Embroidery Studio Crack Free Latest 2025
Wilcom Embroidery Studio Crack Free Latest 2025
Web Designer
 
Why CoTester Is the AI Testing Tool QA Teams Can’t Ignore
Why CoTester Is the AI Testing Tool QA Teams Can’t IgnoreWhy CoTester Is the AI Testing Tool QA Teams Can’t Ignore
Why CoTester Is the AI Testing Tool QA Teams Can’t Ignore
Shubham Joshi
 
Passive House Canada Conference 2025 Presentation [Final]_v4.ppt
Passive House Canada Conference 2025 Presentation [Final]_v4.pptPassive House Canada Conference 2025 Presentation [Final]_v4.ppt
Passive House Canada Conference 2025 Presentation [Final]_v4.ppt
IES VE
 
Catching Wire; An introduction to CBWire 4
Catching Wire; An introduction to CBWire 4Catching Wire; An introduction to CBWire 4
Catching Wire; An introduction to CBWire 4
Ortus Solutions, Corp
 
Best HR and Payroll Software in Bangladesh - accordHRM
Best HR and Payroll Software in Bangladesh - accordHRMBest HR and Payroll Software in Bangladesh - accordHRM
Best HR and Payroll Software in Bangladesh - accordHRM
accordHRM
 
S3 + AWS Athena how to integrate s3 aws plus athena
S3 + AWS Athena how to integrate s3 aws plus athenaS3 + AWS Athena how to integrate s3 aws plus athena
S3 + AWS Athena how to integrate s3 aws plus athena
aianand98
 
AI Agents with Gemini 2.0 - Beyond the Chatbot
AI Agents with Gemini 2.0 - Beyond the ChatbotAI Agents with Gemini 2.0 - Beyond the Chatbot
AI Agents with Gemini 2.0 - Beyond the Chatbot
Márton Kodok
 
Mobile Application Developer Dubai | Custom App Solutions by Ajath
Mobile Application Developer Dubai | Custom App Solutions by AjathMobile Application Developer Dubai | Custom App Solutions by Ajath
Mobile Application Developer Dubai | Custom App Solutions by Ajath
Ajath Infotech Technologies LLC
 
UI/UX Design & Development and Servicess
UI/UX Design & Development and ServicessUI/UX Design & Development and Servicess
UI/UX Design & Development and Servicess
marketing810348
 
Unit Two - Java Architecture and OOPS
Unit Two  -   Java Architecture and OOPSUnit Two  -   Java Architecture and OOPS
Unit Two - Java Architecture and OOPS
Nabin Dhakal
 
Albert Pintoy - A Distinguished Software Engineer
Albert Pintoy - A Distinguished Software EngineerAlbert Pintoy - A Distinguished Software Engineer
Albert Pintoy - A Distinguished Software Engineer
Albert Pintoy
 
Quasar Framework Introduction for C++ develpoers
Quasar Framework Introduction for C++ develpoersQuasar Framework Introduction for C++ develpoers
Quasar Framework Introduction for C++ develpoers
sadadkhah
 
wAIred_LearnWithOutAI_JCON_14052025.pptx
wAIred_LearnWithOutAI_JCON_14052025.pptxwAIred_LearnWithOutAI_JCON_14052025.pptx
wAIred_LearnWithOutAI_JCON_14052025.pptx
SimonedeGijt
 
Hydraulic Modeling And Simulation Software Solutions.pptx
Hydraulic Modeling And Simulation Software Solutions.pptxHydraulic Modeling And Simulation Software Solutions.pptx
Hydraulic Modeling And Simulation Software Solutions.pptx
julia smits
 
Troubleshooting JVM Outages – 3 Fortune 500 case studies
Troubleshooting JVM Outages – 3 Fortune 500 case studiesTroubleshooting JVM Outages – 3 Fortune 500 case studies
Troubleshooting JVM Outages – 3 Fortune 500 case studies
Tier1 app
 
Welcome to QA Summit 2025.
Welcome to QA Summit 2025.Welcome to QA Summit 2025.
Welcome to QA Summit 2025.
QA Summit
 
Aligning Projects to Strategy During Economic Uncertainty
Aligning Projects to Strategy During Economic UncertaintyAligning Projects to Strategy During Economic Uncertainty
Aligning Projects to Strategy During Economic Uncertainty
OnePlan Solutions
 
Medical Device Cybersecurity Threat & Risk Scoring
Medical Device Cybersecurity Threat & Risk ScoringMedical Device Cybersecurity Threat & Risk Scoring
Medical Device Cybersecurity Threat & Risk Scoring
ICS
 
Multi-Agent Era will Define the Future of Software
Multi-Agent Era will Define the Future of SoftwareMulti-Agent Era will Define the Future of Software
Multi-Agent Era will Define the Future of Software
Ivo Andreev
 
Buy vs. Build: Unlocking the right path for your training tech
Buy vs. Build: Unlocking the right path for your training techBuy vs. Build: Unlocking the right path for your training tech
Buy vs. Build: Unlocking the right path for your training tech
Rustici Software
 
Wilcom Embroidery Studio Crack Free Latest 2025
Wilcom Embroidery Studio Crack Free Latest 2025Wilcom Embroidery Studio Crack Free Latest 2025
Wilcom Embroidery Studio Crack Free Latest 2025
Web Designer
 
Why CoTester Is the AI Testing Tool QA Teams Can’t Ignore
Why CoTester Is the AI Testing Tool QA Teams Can’t IgnoreWhy CoTester Is the AI Testing Tool QA Teams Can’t Ignore
Why CoTester Is the AI Testing Tool QA Teams Can’t Ignore
Shubham Joshi
 
Passive House Canada Conference 2025 Presentation [Final]_v4.ppt
Passive House Canada Conference 2025 Presentation [Final]_v4.pptPassive House Canada Conference 2025 Presentation [Final]_v4.ppt
Passive House Canada Conference 2025 Presentation [Final]_v4.ppt
IES VE
 
Catching Wire; An introduction to CBWire 4
Catching Wire; An introduction to CBWire 4Catching Wire; An introduction to CBWire 4
Catching Wire; An introduction to CBWire 4
Ortus Solutions, Corp
 

JPA and Hibernate Performance Tips

  • 1. @vlad_mihalcea vladmihalcea.com JPA and Hibernate Performance Tips
  • 3. @vlad_mihalcea vladmihalcea.com Mappings CC BY-SA 2.0 - https://www.flickr.com/photos/47515486@N05/44129053595/
  • 4. @vlad_mihalcea vladmihalcea.com TABLE generator @Entity public class Post { @Id @GeneratedValue(strategy = GenerationType.TABLE) private Long id; private String title; //Getters and setters omitted for brevity }
  • 5. @vlad_mihalcea vladmihalcea.com TABLE generator CREATE TABLE hibernate_sequences ( sequence_name (255) NOT NULL, next_val, PRIMARY KEY (sequence_name) ) CREATE TABLE post ( id NOT NULL, title (255), PRIMARY KEY (id) )
  • 6. @vlad_mihalcea vladmihalcea.com TABLE generator public IntegralDataTypeHolder getNextValue() { return session.getTransactionCoordinator().createIsolationDelegate() .delegateWork(new AbstractReturningWork<IntegralDataTypeHolder>() { public IntegralDataTypeHolder execute( Connection connection) throws SQLException { … }, true ); } for (int i = 0; i < 3; i++) { Post post = new Post(); post.setTitle( String.format("High-Performance Java Persistence, Part %d", i + 1) ); entityManager.persist(post); }
  • 7. @vlad_mihalcea vladmihalcea.com SELECT tbl.next_val FROM hibernate_sequences tbl WHERE tbl.sequence_name = 'default' FOR UPDATE INSERT INTO hibernate_sequences (sequence_name, next_val) VALUES ('default', 1) UPDATE hibernate_sequences SET next_val = 2 WHERE next_val = 1 AND sequence_name = 'default' SELECT tbl.next_val FROM hibernate_sequences tbl WHERE tbl.sequence_name = 'default' FOR UPDATE UPDATE hibernate_sequences SET next_val = 3 WHERE next_val = 2 AND sequence_name = 'default' SELECT tbl.next_val FROM hibernate_sequences tbl WHERE tbl.sequence_name = 'default' FOR UPDATE UPDATE hibernate_sequences SET next_val = 4 WHERE next_val = 3 AND sequence_name = 'default' TABLE generator
  • 8. @vlad_mihalcea vladmihalcea.com INSERT INTO post (title, id) VALUES ('High-Performance Java Persistence, Part 1', 1) INSERT INTO post (title, id) VALUES ('High-Performance Java Persistence, Part 2', 2) INSERT INTO post (title, id) VALUES ('High-Performance Java Persistence, Part 3', 3) TABLE generator
  • 11. @vlad_mihalcea vladmihalcea.com AUTO Generator @Entity public class Post { @Id @GeneratedValue(strategy = GenerationType.AUTO) private Long id; private String title; //Getters and setters omitted for brevity }
  • 12. @vlad_mihalcea vladmihalcea.com AUTO Generator • Prior to Hibernate 5 – native strategy. • Hibernate 5 – SequenceStyleGenerator strategy (falls back to TABLE)
  • 13. @vlad_mihalcea vladmihalcea.com AUTO Generator – Hibernate 5 and MySQL @Id @GeneratedValue(generator="native") @GenericGenerator(name = "native", strategy = "native") private Long id; INSERT INTO post (title) VALUES ('High-Performance Java Persistence, Part 1') INSERT INTO post (title) VALUES ('High-Performance Java Persistence, Part 2') INSERT INTO post (title) VALUES ('High-Performance Java Persistence, Part 3')
  • 14. @vlad_mihalcea vladmihalcea.com Identifier portability – annotation mapping @Entity(name = "Post") @Table(name = "post") public class Post { @Id @GeneratedValue(generator = "sequence", strategy = GenerationType.SEQUENCE) @SequenceGenerator(name = "sequence", allocationSize = 10) private Long id; private String title; //Getters and setters omitted for brevity }
  • 15. @vlad_mihalcea vladmihalcea.com Identifier portability – XML mapping <?xml version="1.0" encoding="UTF-8"?> <entity-mappings xmlns="http://xmlns.jcp.org/xml/ns/persistence/orm" xmlns:xsi=http://www.w3.org/2001/XMLSchema-instance xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence/orm_2_2.xsd" version="2.2"> <package>com.vladmihalcea.book.hpjp.hibernate.identifier.global</package> <entity class="Post" access="FIELD"> <attributes> <id name="id"> <generated-value strategy="IDENTITY"/> </id> </attributes> </entity> </entity-mappings
  • 16. @vlad_mihalcea vladmihalcea.com Custom types – IP address column • IP address stored in the Classless Inter-Domain Routing format • VARCHAR(18) • BIGINT column encoding – 4 bytes (e.g. 192.168.123.231) + 1 byte (e.g. 24) • PostgreSQL cidr or inet type (requires 7 bytes)
  • 17. @vlad_mihalcea vladmihalcea.com Custom types – PostgreSQL inet column Event matchingEvent = (Event) entityManager .createNativeQuery( "SELECT e.* " + "FROM event e " + "WHERE " + " e.ip && CAST(:network AS inet) = TRUE") .setParameter("network", "192.168.0.1/24") .getSingleResult(); assertEquals("192.168.0.123", matchingEvent.getIp().getAddress());
  • 18. @vlad_mihalcea vladmihalcea.com Custom types – PostgreSQL inet column @Entity(name = "Event") @Table(name = "event") @TypeDef(typeClass = IPv4Type.class, defaultForType = IPv4.class) public class Event { @Id @GeneratedValue private Long id; @Column(name = "ip", columnDefinition = "inet") private IPv4 ip; //Getters and setters omitted for brevity }
  • 19. @vlad_mihalcea vladmihalcea.com The hibernate-types project <dependency> <groupId>com.vladmihalcea</groupId> <artifactId>hibernate-types-52</artifactId> <version>${hibernate-types.version}</version> </dependency> <dependency> <groupId>com.vladmihalcea</groupId> <artifactId>hibernate-types-5</artifactId> <version>${hibernate-types.version}</version> </dependency>
  • 20. @vlad_mihalcea vladmihalcea.com JSON for unstructured data @Entity(name = "Book") @Table(name = "book") @TypeDef(typeClass = JsonNodeBinaryType.class, defaultForType = JsonNode.class) public class Book { @Id @GeneratedValue private Long id; @NaturalId private String isbn; @Column(columnDefinition = "jsonb") private JsonNode properties; //Getters and setters omitted for brevity }
  • 21. @vlad_mihalcea vladmihalcea.com JSON for unstructured data Book book = new Book(); book.setIsbn("978-9730228236"); book.setProperties( JacksonUtil.toJsonNode( "{" + " "title": "High-Performance Java Persistence"," + " "author": "Vlad Mihalcea"," + " "publisher": "Amazon"," + " "price": 44.99" + "}" ) );
  • 22. @vlad_mihalcea vladmihalcea.com JSON for unstructured data Book book = entityManager.unwrap(Session.class).bySimpleNaturalId(Book.class) .load("978-9730228236"); book.setProperties( JacksonUtil.toJsonNode( "{" + " "title": "High-Performance Java Persistence"," + " "author": "Vlad Mihalcea"," + " "publisher": "Amazon"," + " "price": 44.99," + " "url": "https://www.amzn.com/973022823X/"" + "}" ) );
  • 23. @vlad_mihalcea vladmihalcea.com Statement caching CC BY 2.0 - https://www.flickr.com/photos/southbeachcars/16065861514/
  • 25. @vlad_mihalcea vladmihalcea.com Oracle server-side statement caching • Soft parse • Hard parse • Bind peeking • Adaptive cursor sharing (since 11g)
  • 26. @vlad_mihalcea vladmihalcea.com SQL Server server-side statement caching • Execution plan cache • Parameter sniffing • Prepared statements should use the qualified object name SELECT * FROM etl.dbo.task WHERE status = ?
  • 27. @vlad_mihalcea vladmihalcea.com PostgreSQL server-side statement caching • Prior to 9.2 – execution plan cache • 9.2 – deferred optimization • The prepareThreshold connection property
  • 28. @vlad_mihalcea vladmihalcea.com MySQL server-side statement caching • No execution plan cache • Since Connector/J 5.0.5 PreparedStatements are emulated • To activate server-side prepared statements: • useServerPrepStmts • cachePrepStmts
  • 29. @vlad_mihalcea vladmihalcea.com Client-side statement caching • Recycling Statement, PreparedStatement or CallableStatement objects • Reusing database cursors
  • 30. @vlad_mihalcea vladmihalcea.com Oracle implicit client-side statement caching • Connection-level cache • PreparedStatement and CallabledStatement only • Caches metadata only connectionProperties.put( "oracle.jdbc.implicitStatementCacheSize", Integer.toString(cacheSize)); dataSource.setConnectionProperties(connectionProperties);
  • 31. @vlad_mihalcea vladmihalcea.com Oracle implicit client-side statement caching • Once enabled, all statements are cached. • Can be disabled on a per statement basis if (statement.isPoolable()) { statement.setPoolable(false); }
  • 32. @vlad_mihalcea vladmihalcea.com Oracle explicit client-side statement caching • Caches both metadata, execution state and data OracleConnection oracleConnection = (OracleConnection) connection; oracleConnection.setExplicitCachingEnabled(true); oracleConnection.setStatementCacheSize(cacheSize);
  • 33. @vlad_mihalcea vladmihalcea.com Oracle explicit client-side statement caching PreparedStatement statement = oracleConnection. getStatementWithKey(SELECT_POST_KEY); if (statement == null) { statement = connection.prepareStatement(SELECT_POST); } try { statement.setInt(1, 10); statement.execute(); } finally { ((OraclePreparedStatement) statement).closeWithKey(SELECT_POST_KEY); }
  • 34. @vlad_mihalcea vladmihalcea.com SQL Server client-side statement caching • The SQL Server JDBC driver version 6.3 added support for statement caching. • Prepared Statement caching is disabled by default. connection.setStatementPoolingCacheSize(10); connection.setDisableStatementPooling(false);
  • 35. @vlad_mihalcea vladmihalcea.com PostgreSQL Server client-side statement caching • PostgreSQL JDBC Driver 9.4-1202 makes client-side statement connection-bound instead of statement-bound • Configurable: • preparedStatementCacheQueries (default is 256) • preparedStatementCacheSizeMiB (default is 5MB) • Statement.setPoolable(false) is not supported
  • 36. @vlad_mihalcea vladmihalcea.com MySQL Server client-side statement caching • Configurable: • cachePrepStmts (default is false) Required for server-side statement caching as well • prepStmtCacheSize (default is 25) • prepStmtCacheSqlLimit (default is 256) • Statement.setPoolable(false) works for server-side statements only
  • 37. @vlad_mihalcea vladmihalcea.com Statement caching gain (one minute interval) Database System No Caching Throughput (SPM) Caching Throughput (SPM) Percentage Gain DB_A 419 833 507 286 20.83% DB_B 194 837 303 100 55.56% DB_C 116 708 166 443 42.61% DB_D 15 522 15 550 0.18%
  • 38. @vlad_mihalcea vladmihalcea.com Queries CC BY 2.0 - https://www.flickr.com/photos/justinbaeder/5317820857/
  • 39. @vlad_mihalcea vladmihalcea.com Criteria API literal handling CriteriaBuilder cb = entityManager.getCriteriaBuilder(); CriteriaQuery<Book> cq = cb.createQuery(Book.class); Root<Book> root = cq.from(Book.class); cq.select(root); cq.where(cb.equal(root.get("name"), "High-Performance Java Persistence")); Book book = entityManager.createQuery(cq).getSingleResult(); SELECT b.id AS id1_0_, b.isbn AS isbn2_0_, b.name AS name3_0_ FROM book b WHERE b.name = ?
  • 40. @vlad_mihalcea vladmihalcea.com Criteria API literal handling CriteriaBuilder cb = entityManager.getCriteriaBuilder(); CriteriaQuery<Book> cq = cb.createQuery(Book.class); Root<Book> root = cq.from(Book.class); cq.select(root); cq.where(cb.equal(root.get("isbn"), 978_9730228236L)); Book book = entityManager.createQuery(cq).getSingleResult(); SELECT b.id AS id1_0_, b.isbn AS isbn2_0_, b.name AS name3_0_ FROM book b WHERE b.isbn = 9789730228236
  • 42. @vlad_mihalcea vladmihalcea.com Criteria API literal handling <property name="hibernate.criteria.literal_handling_mode" value="bind" /> <property name="hibernate.criteria.literal_handling_mode" value="inline" /> <property name="hibernate.criteria.literal_handling_mode" value="auto" />
  • 43. @vlad_mihalcea vladmihalcea.com IN query padding optimization List<Post> getPostByIds(EntityManager entityManager, Integer... ids) { return entityManager.createQuery( "select p " + "from Post p " + "where p.id in :ids", Post.class) .setParameter("ids", Arrays.asList(ids)) .getResultList(); }
  • 44. @vlad_mihalcea vladmihalcea.com IN query padding optimization SELECT p.id AS id1_0_, p.title AS title2_0_ FROM post p WHERE p.id IN (?, ?, ?) SELECT p.id AS id1_0_, p.title AS title2_0_ FROM post p WHERE p.id IN (?, ?, ?, ?) assertEquals(3, getPostByIds(entityManager, 1, 2, 3).size()); assertEquals(4, getPostByIds(entityManager, 1, 2, 3, 4).size());
  • 45. @vlad_mihalcea vladmihalcea.com IN query padding optimization SELECT p.id AS id1_0_, p.title AS title2_0_ FROM post p WHERE p.id IN (?, ?, ?, ?, ?) SELECT p.id AS id1_0_, p.title AS title2_0_ FROM post p WHERE p.id IN (?, ?, ?, ?, ?, ?) assertEquals(5, getPostByIds(entityManager, 1, 2, 3, 4, 5).size()); assertEquals(6, getPostByIds(entityManager, 1, 2, 3, 4, 5, 6).size());
  • 47. @vlad_mihalcea vladmihalcea.com IN query padding optimization <property name="hibernate.query.in_clause_parameter_padding" value="true" /> SELECT p.id AS id1_0_, p.title AS title2_0_ FROM post p WHERE p.id IN (?, ?, ?, ?) -- Params: (1, 2, 3, 3) SELECT p.id AS id1_0_, p.title AS title2_0_ FROM post p WHERE p.id IN (?, ?, ?, ?) -- Params: (1, 2, 3, 4) assertEquals(3, getPostByIds(entityManager, 1, 2, 3).size()); assertEquals(4, getPostByIds(entityManager, 1, 2, 3, 4).size());
  • 48. @vlad_mihalcea vladmihalcea.com IN query padding optimization assertEquals(5, getPostByIds(entityManager, 1, 2, 3, 4, 5).size()); SELECT p.id AS id1_0_, p.title AS title2_0_ FROM post p WHERE p.id IN (?, ?, ?, ?, ?, ?, ?, ?) -- Params: (1, 2, 3, 4, 5, 5, 5, 5) assertEquals(6, getPostByIds(entityManager, 1, 2, 3, 4, 5, 6).size()); SELECT p.id AS id1_0_, p.title AS title2_0_ FROM post p WHERE p.id IN (?, ?, ?, ?, ?, ?, ?, ?) -- Params: (1, 2, 3, 4, 5, 6, 6, 6)
  • 49. @vlad_mihalcea vladmihalcea.com Query plan cache • Entity queries (JPQL, Criteria API) need to be compiled to SQL • Configurable: • hibernate.query.plan_cache_max_size (2048) • hibernate.query.plan_parameter_metadata_max_size (128)
  • 51. @vlad_mihalcea vladmihalcea.com Native SQL query plan cache improvement
  • 52. @vlad_mihalcea vladmihalcea.com JPQL DISTINCT scalar query List<Integer> publicationYears = entityManager.createQuery( "select distinct year(p.createdOn) " + "from Post p " + "order by year(p.createdOn)", Integer.class) .getResultList(); SELECT DISTINCT extract(YEAR FROM p.created_on) AS col_0_0_ FROM post p ORDER BY (YEAR FROM p.created_on)
  • 53. @vlad_mihalcea vladmihalcea.com JPQL DISTINCT entity query List<Post> posts = entityManager.createQuery( "select distinct p " + "from Post p " + "left join fetch p.comments " + "where p.title = :title", Post.class) .setParameter("title", "High-Performance Java Persistence") .getResultList(); SELECT DISTINCT p.id AS id1_0_0_, pc.id AS id1_1_1_, p.title AS title2_0_0_, pc.review AS review2_1_1_, pc.post_id AS post_id3_1_0__, pc.id AS id1_1_0__ FROM post p LEFT OUTER JOIN post_comment pc ON p.id=pc.post_id WHERE p.title = ?
  • 55. @vlad_mihalcea vladmihalcea.com JPQL DISTINCT entity query List<Post> posts = entityManager.createQuery( "select distinct p " + "from Post p " + "left join fetch p.comments " + "where p.title = :title", Post.class) .setParameter("title", "High-Performance Java Persistence") .setHint(QueryHints.HINT_PASS_DISTINCT_THROUGH, false) .getResultList(); SELECT p.id AS id1_0_0_, pc.id AS id1_1_1_, p.title AS title2_0_0_, pc.review AS review2_1_1_, pc.post_id AS post_id3_1_0__, pc.id AS id1_1_0__ FROM post p LEFT OUTER JOIN post_comment pc ON p.id=pc.post_id WHERE p.title = ?
  • 57. @vlad_mihalcea vladmihalcea.com Fetching CC BY 2.0 - https://www.flickr.com/photos/bala_/3544603505/
  • 60. @vlad_mihalcea vladmihalcea.com Persistence Context size //session-level configuration Session session = entityManager.unwrap(Session.class); session.setDefaultReadOnly(true); //query-level configuration List<Post> posts = entityManager.createQuery( "select p from Post p", Post.class) .setHint(QueryHints.HINT_READONLY, true) .getResultList();
  • 61. @vlad_mihalcea vladmihalcea.com @Transactional(readOnly = true) public List<Post> findAllByTitle(String title) { List<Post> posts = postDAO.findByTitle(title); org.hibernate.engine.spi.PersistenceContext persistenceContext = getHibernatePersistenceContext(); for(Post post : posts) { assertTrue(entityManager.contains(post)); EntityEntry entityEntry = persistenceContext.getEntry(post); assertNull(entityEntry.getLoadedState()); } return posts; } Spring 5.1 read-only optimization
  • 62. @vlad_mihalcea vladmihalcea.com Fetching – Pagination • JPA / Hibernate API works for both entity and native SQL queries List<PostCommentSummary> summaries = entityManager.createQuery( "select new PostCommentSummary( " + " p.id, p.title, c.review ) " + "from PostComment c " + "join c.post p") .setFirstResult(pageStart) .setMaxResults(pageSize) .getResultList();
  • 63. @vlad_mihalcea vladmihalcea.com Fetching – 100k vs 100 rows Fetch all Fetch limit 0 500 1000 1500 2000 2500 3000 3500 4000 4500 5000 Time(ms) DB_A DB_B DB_C DB_D
  • 65. @vlad_mihalcea vladmihalcea.com JPA 2.2 Streaming default Stream getResultStream() { return getResultList().stream(); } final ScrollableResultsImplementor scrollableResults = scroll( ScrollMode.FORWARD_ONLY );
  • 66. @vlad_mihalcea vladmihalcea.com JDBC-level streaming support • You still need to consider the Statement.setFetchSize. • On MySQL, you need to set it to Integer.MIN_VALUE. • On PostgreSQL, you need to set it to a positive integer value. • What about the Execution Plan?
  • 67. @vlad_mihalcea vladmihalcea.com JPA 2.2 Streaming – Execution Plans List<String> executionPlanLines = doInJPA(entityManager -> { try(Stream<String> postStream = entityManager .createNativeQuery( "EXPLAIN ANALYZE " + "SELECT p " + "FROM post p " + "ORDER BY p.created_on DESC") .setHint(QueryHints.HINT_FETCH_SIZE, 50) .getResultStream() ) { return postStream.limit(50).collect(Collectors.toList()); } }); CREATE INDEX idx_post_created_on ON post (created_on DESC)
  • 68. @vlad_mihalcea vladmihalcea.com JPA 2.2 Streaming – Execution Plans LOGGER.info( "Execution plan: {}", executionPlanLines .stream() .collect(Collectors.joining( "n" )) ); Execution plan: Sort (cost=65.53..66.83 rows=518 width=564) (actual time=2.876..3.399 rows=5000 loops=1) Sort Key: created_on DESC Sort Method: quicksort Memory: 896kB -> Seq Scan on post p (cost=0.00..42.18 rows=518 width=564) (actual time=0.050..1.371 rows=5000 loops=1) Planning time: 1.586 ms Execution time: 4.061 ms
  • 69. @vlad_mihalcea vladmihalcea.com JPA 2.2 Streaming – Execution Plans List<String> executionPlanLines = doInJPA(entityManager -> { return entityManager .createNativeQuery( "EXPLAIN ANALYZE " + "SELECT p " + "FROM post p " + "ORDER BY p.created_on DESC") .setMaxResults(50) .getResultList(); }); LOGGER.info("Execution plan: {}", executionPlanLines .stream() .collect(Collectors.joining("n")) );
  • 70. @vlad_mihalcea vladmihalcea.com JPA 2.2 Streaming – Execution Plans Execution plan: Limit (cost=0.28..25.35 rows=50 width=564) (actual time=0.038..0.051 rows=50 loops=1) -> Index Scan using idx_post_created_on on post p (cost=0.28..260.04 rows=518 width=564) (actual time=0.037..0.049 rows=50 loops=1) Planning time: 1.511 ms Execution time: 0.148 ms
  • 71. @vlad_mihalcea vladmihalcea.com Fetching – Open Session in View Anti-Pattern
  • 72. @vlad_mihalcea vladmihalcea.com Fetching – Open Session in View Anti-Pattern
  • 73. @vlad_mihalcea vladmihalcea.com Fetching – Temporary Session Anti-Pattern • “Band aid” for LazyInitializationException • One temporary Session/Connection for every lazily fetched association <property name="hibernate.enable_lazy_load_no_trans" value="true"/>
  • 74. @vlad_mihalcea vladmihalcea.com Batching CC BY-SA 2.0 - https://www.flickr.com/photos/dozodomo/6975654335/
  • 78. @vlad_mihalcea vladmihalcea.com Batch processing – flush-clear-commit try { entityManager.getTransaction().begin(); for ( int i = 0; i < entityCount; ++i ) { if ( i > 0 && i % batchSize == 0 ) { flush( entityManager ); } entityManager.persist( new Post( String.format( "Post %d", i + 1 ) ) ); } entityManager.getTransaction().commit(); } catch (RuntimeException e) { if ( entityManager.getTransaction().isActive()) { entityManager.getTransaction().rollback(); } throw e; } finally { entityManager.close(); }
  • 79. @vlad_mihalcea vladmihalcea.com private void flush(EntityManager entityManager) { entityManager.flush(); entityManager.clear(); entityManager.getTransaction().commit(); entityManager.getTransaction().begin(); } Batch processing – flush and commit
  • 80. @vlad_mihalcea vladmihalcea.com Hibernate batching – default behavior for (int i = 0; i < 3; i++) { entityManager.persist( new Post(String.format("Post no. %d", i + 1)) ); } INSERT INTO post (title, id) VALUES ('Post no. 1', 1) INSERT INTO post (title, id) VALUES ('Post no. 2', 2) INSERT INTO post (title, id) VALUES ('Post no. 3', 3)
  • 81. @vlad_mihalcea vladmihalcea.com Enable JDBC batching <property name="hibernate.jdbc.batch_size" value="5"/> Query: ["INSERT INTO post (title, id) VALUES (?, ?)"], Params: [('Post no. 1', 1), ('Post no. 2', 2), ('Post no. 3', 3)] entityManager.unwrap(Session.class).setJdbcBatchSize(10); for (long i = 0; i < 10; ++i) { Post post = new Post(); post.setTitle(String.format("Post nr %d", i)); entityManager.persist(post); }
  • 82. @vlad_mihalcea vladmihalcea.com PostgreSQL batch statements log_statement = 'all' LOG: execute S_2: insert into post (title, id) values ($1, $2) DETAIL: parameters: $1 = 'Post no. 1', $2 = '1' LOG: execute S_2: insert into post (title, id) values ($1, $2) DETAIL: parameters: $1 = 'Post no. 2', $2 = '2' LOG: execute S_2: insert into post (title, id) values ($1, $2) DETAIL: parameters: $1 = 'Post no. 3', $2 = '3'
  • 83. @vlad_mihalcea vladmihalcea.com PostgreSQL rewrite batch statements PGSimpleDataSource dataSource = (PGSimpleDataSource) dataSource(); dataSource.setReWriteBatchedInserts(true); LOG: execute <unnamed>: insert into post (title, id) values ($1, $2),($3, $4),($5, $6) DETAIL: parameters: $1 = 'Post no. 1', $2 = '1’, $3 = 'Post no. 2', $4 = '2’, $5 = 'Post no. 3', $6 = '3'
  • 84. @vlad_mihalcea vladmihalcea.com Default UPDATE - Post entity mapping @Entity(name = "Post") @Table(name = "post") public class Post { @Id private Long id; private String title; private long likes; //Getters and setters omitted for brevity }
  • 85. @vlad_mihalcea vladmihalcea.com Default UPDATE - Post entity data Post post1 = new Post(); post1.setId(1L); post1.setTitle("High-Performance Java Persistence"); entityManager.persist(post1); Post post2 = new Post(); post2.setId(2L); post2.setTitle("Java Persistence with Hibernate"); entityManager.persist(post2);
  • 86. @vlad_mihalcea vladmihalcea.com Default UPDATE - statement batching Post post1 = entityManager.find(Post.class, 1L); post1.setTitle("High-Performance Java Persistence 2nd Edition"); Post post2 = entityManager.find(Post.class, 2L); post2.setLikes(12); entityManager.flush(); Query :[ "update post set likes=?, title=? where id=?" ], Params:[ (0, High-Performance Java Persistence 2nd Edition, 1), (12, Java Persistence with Hibernate, 2) ]
  • 87. @vlad_mihalcea vladmihalcea.com Default UPDATE disadvantages • Column size • Indexes • Replication • Undo and redo log • Triggers
  • 88. @vlad_mihalcea vladmihalcea.com Hibernate dynamic update @Entity(name = "Post") @Table(name = "post") @DynamicUpdate public class Post { @Id private Long id; private String title; private long likes; //Getters and setters omitted for brevity }
  • 89. @vlad_mihalcea vladmihalcea.com Hibernate dynamic update Query:["update post set title=? where id=?"], Params:[(High-Performance Java Persistence 2nd Edition, 1)] Query:["update post set likes=? where id=?"], Params:[(12, 2)] Post post1 = entityManager.find(Post.class, 1L); post1.setTitle("High-Performance Java Persistence 2nd Edition"); Post post2 = entityManager.find(Post.class, 2L); post2.setlikes(12); entityManager.flush();
  • 90. @vlad_mihalcea vladmihalcea.com Updating detached entities - Post and PostComment List<Post> posts = doInJPA(entityManager -> { return entityManager.createQuery( "select p " + "from Post p " + "join fetch p.comments ", Post.class) .getResultList(); }); for (Post post: posts) { post.setTitle("Vlad Mihalcea's " + post.getTitle()); for (PostComment comment: post.getComments()) { comment.setReview(comment.getReview() + " read!"); } }
  • 91. @vlad_mihalcea vladmihalcea.com • JPA merge • Hibernate update JPA merge and Hibernate update for (Post post: posts) { entityManager.merge(post); } Session session = entityManager.unwrap(Session.class); for (Post post: posts) { session.update(post); }
  • 92. @vlad_mihalcea vladmihalcea.com JPA merge – SELECT statements SELECT p.id AS id1_0_1_, p.title AS title2_0_1_, c.post_id AS post_id3_1_3_, c.id AS id1_1_3_, c.review AS review2_1_0_ FROM post p LEFT OUTER JOIN post_comment c ON p.id = c.post_id WHERE p.id = 1 SELECT p.id AS id1_0_1_, p.title AS title2_0_1_, c.post_id AS post_id3_1_3_, c.id AS id1_1_3_, c.review AS review2_1_0_ FROM post p LEFT OUTER JOIN post_comment c ON p.id = c.post_id WHERE p.id = 3 SELECT p.id AS id1_0_1_, p.title AS title2_0_1_, c.post_id AS post_id3_1_3_, c.id AS id1_1_3_, c.review AS review2_1_0_ FROM post p LEFT OUTER JOIN post_comment c ON p.id = c.post_id WHERE p.id = 5 …
  • 93. @vlad_mihalcea vladmihalcea.com JPA merge – UPDATE statements Query:[ "update post set title=? where id=?" ], Params:[ (Vlad Mihalcea's High-Performance Java Persistence, Part no. 0, 1), (Vlad Mihalcea's High-Performance Java Persistence, Part no. 1, 3), (Vlad Mihalcea's High-Performance Java Persistence, Part no. 2, 5) ] Query:[ "update post_comment set post_id=?, review=? where id=?" ], Params:[ (1, Excellent read!, 2), (3, Excellent read!, 4), (5, Excellent read!, 6) ]
  • 94. @vlad_mihalcea vladmihalcea.com Hibernate-specific update operation Query:[ "update post set title=? where id=?" ], Params:[ (Vlad Mihalcea's High-Performance Java Persistence, Part no. 0, 1), (Vlad Mihalcea's High-Performance Java Persistence, Part no. 1, 3), (Vlad Mihalcea's High-Performance Java Persistence, Part no. 2, 5) ] Query:[ "update post_comment set post_id=?, review=? where id=?" ], Params:[ (1, Excellent read!, 2), (3, Excellent read!, 4), (5, Excellent read!, 6) ]
  • 95. @vlad_mihalcea vladmihalcea.com Connections CC BY 2.0 - https://www.flickr.com/photos/justinbaeder/5317820857/
  • 97. @vlad_mihalcea vladmihalcea.com Immediate connection acquisition @PersistenceContext private EntityManager entityManager; @Transactional public void importForecasts(String dataFilePath) { Document forecastXmlDocument = readXmlDocument( dataFilePath ); List<Forecast> forecasts = parseForecasts(forecastXmlDocument); for(Forecast forecast : forecasts) { entityManager.persist( forecast ); } }
  • 98. @vlad_mihalcea vladmihalcea.com Resource-local delay connection acquisition <property name="hibernate.connection.provider_disables_autocommit" value="true" /> HikariConfig hikariConfig = new HikariConfig(); hikariConfig.setDataSourceClassName(dataSourceClassName); hikariConfig.setDataSourceProperties(dataSourceProperties); hikariConfig.setMinimumPoolSize(minPoolSize); hikariConfig.setMaximumPoolSize(maxPoolSize); hikariConfig.setAutoCommit(false); DataSource datasource = new HikariDataSource(hikariConfig);
  • 100. @vlad_mihalcea vladmihalcea.com Thank you • Twitter: @vlad_mihalcea • Blog: https://vladmihalcea.com • Courses: https://vladmihalcea.com/courses • Book: https://vladmihalcea.com/books/high-performance-java-persistence/