Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Performance Oriented Spring Data JPA & Hibernate

Performance Oriented Spring Data JPA & Hibernate

Watch on YouTube 👉 https://www.youtube.com/watch?v=exqfB1WaqIw

Hibernate - the most popular persistence technology for Java - also the most controversial one. Some people love it, some people hate it. No matter in which group you are, the chances you will work in Hibernate in at least one project are close to 100% - and you have no other choice than learning it. Not only the basics, but most importantly - how to leverage the power of Hibernate without sacrificing application and database performance.
In this session you will learn how to configure Hibernate and Spring Data JPA for efficient database connection management, what is a N+1 problem and how to solve it, how and when to use projections for fast data retrieval ... and more!

Maciej Walkowiak

March 15, 2024
Tweet

More Decks by Maciej Walkowiak

Other Decks in Programming

Transcript

  1. Maciej Walkowiak | @maciejwalkowiak Why so slow? • Poor database

    connection management • Too many queries • Slow queries • Wrong JPA mappings • Fetching more than needed
  2. Maciej Walkowiak | @maciejwalkowiak Database JDBC Driver DataSource Application Database

    JDBC Driver DataSource Application get connection get connection get connection connection connection connection Network
  3. Maciej Walkowiak | @maciejwalkowiak Database JDBC Driver DataSource Application Database

    JDBC Driver DataSource Application get connection get connection get connection connection connection connection Network • TCP Handshake • TLS negotiation • Authentication
  4. Maciej Walkowiak | @maciejwalkowiak On the Database side (Postgres) •

    Each connection sparks a new OS process • Consumes 5-10MB of RAM • CPU context switching
  5. Maciej Walkowiak | @maciejwalkowiak • On application startup, creates a

    pool of physical connections • Reuses already open connections • Creates more connections, when pool is exhausted Connection Pooling
  6. Maciej Walkowiak | @maciejwalkowiak Connection Pool DataSource Application Connection Pool

    DataSource Application get connection acquire connection connection connection
  7. Maciej Walkowiak | @maciejwalkowiak • Tomcat handles requests with 200

    threads • HikariCP default pool size is 10 How big is your pool?
  8. If you have 10,000 front-end users, having a connection pool

    of 10,000 would be shear insanity. 1000 still horrible. Even 100 connections, overkill. You want a small pool of a few dozen connections at most, and you want the rest of the application threads blocked on the pool awaiting connections. https://github.com/brettwooldridge/HikariCP/wiki/About-Pool-Sizing
  9. Maciej Walkowiak | @maciejwalkowiak • Turn off `spring.jpa.open-in-view` • Call

    external services outside of database transaction • Turn off auto-commit • Be very careful with @Transactional(propagation = REQUIRES_NEW) • Use TransactionTemplate when you need more control Summary
  10. Maciej Walkowiak | @maciejwalkowiak Summary • Avoid select on insert

    with @Version or implement Persistable • Use Repository#getReferenceById when you need … references • Always use FetchType.LAZY on @ManyToOne, @ManyToMany • Explicitly fetch associations with fetch join or @EntityGraph • Use @DynamicUpdate for table with large number of columns
  11. Maciej Walkowiak | @maciejwalkowiak Entities - goods and bads •

    Fetching more data than needed (even with LAZY fetch types) - 😢 • Loaded entities are stored in JPA Persistence Context - memory 🥺 • Dirty Tracking - CPU 😡 • The risk of N+1 - Database 😱 • Handles business logic and enforces invariants
  12. Maciej Walkowiak | @maciejwalkowiak @Entity public class Account { @Id

    private String id; private String iban; private String firstName; private String lastName; @ElementCollection @CollectionTable( name = "phone_number", joinColumns = @JoinColumn(name = “account_id") ) private List<PhoneNumber> phoneNumbers; } {"id":"sender-id","firstName":"John","lastName":"Doe"} Expected Response: record NamesOnly(String id, String firstName, String lastName) {} Projection Class
  13. Maciej Walkowiak | @maciejwalkowiak record NamesOnly(String id, String firstName, String

    lastName) {} Projection Class public interface AccountRepository extends JpaRepository<Account, String> { NamesOnly findNamesOnlyById(String id); } Repository
  14. Maciej Walkowiak | @maciejwalkowiak @Query("select new NamesOnly(a.id, a.firstName, a.lastName) from

    Account a where a.id = :id") NamesOnly findNamesOnlyById(String id);
  15. Maciej Walkowiak | @maciejwalkowiak @Query(value = "select id, first_name, last_name

    from account where id = :id", nativeQuery = true) NamesOnly findNamesOnlyById(String id); interface NamesOnly { String getId(); String getFirstName(); String getLastName(); } 😳
  16. Maciej Walkowiak | @maciejwalkowiak public interface AccountRepository extends JpaRepository<Account, String>

    { NamesOnly findNamesOnlyById(String id); AccountWithState findAccountWithStateById(String id); }
  17. Maciej Walkowiak | @maciejwalkowiak public interface AccountRepository extends JpaRepository<Account, String>

    { NamesOnly findNamesOnlyById(String id); AccountWithState findAccountWithStateById(String id); AccountDTO findAccountDtoById(String id); }
  18. Maciej Walkowiak | @maciejwalkowiak public interface AccountRepository extends JpaRepository<Account, String>

    { NamesOnly findNamesOnlyById(String id); AccountWithState findAccountWithStateById(String id); AccountDTO findAccountDtoById(String id); AccountLight findLightAccountById(String id); } 😳
  19. Maciej Walkowiak | @maciejwalkowiak public interface AccountRepository extends JpaRepository<Account, String>

    { <T> T findById(String id, Class<T> clazz); } 🥴 … but no custom query
  20. Maciej Walkowiak | @maciejwalkowiak Takeaways • JPA & Hibernate are

    NOT easy • Get connections management right • Log queries during development • Consider getting Hibernate Optimiser from Vlad or using QuickPerf for testing • Use projections for reading data