Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.
@jkubrynski / kubrynski.com
JPA - BEYOND COPY-PASTE
JAKUB KUBRYNSKI
jk@devskiller.com / @jkubrynski / http://kubrynski.com
WHOAMI
CO-FOUNDER OF DEVSKILLER
TRAINER AT BOTTEGA
DEVOXX.PL PROGRAM COMMITTEE
CO-AUTHOR OF SPRING CLOUD CONTRACT
@Entity
public class Product {
    @Id
    @GeneratedValue
    private Long id;
    @Column
    private String name;
    /...
@Entity
public class Product {
    @Id
    @GeneratedValue
    private Long id;
    @Column // it does exactly nothing
   ...
@Transactional @Service
public class ProductService {
    public void updatePrice(Long productId, Money newPrice) {
      ...
@Transactional @Service
public class ProductService {
    public void updatePrice(Long productId, Money newPrice) {
      ...
FIELDS VS GETTERS
@Entity
public class Product {
    private Long id;
    private String name;
    @Id
    public Long get...
MIXED ACCESS
@Entity
@Access(AccessType.FIELD)
public class Product {
    private Long id;
    private String name;
    @I...
@Entity
public class Order {
}
@Entity(name = "orders")
public class Order {
}
@Entity(name = "orders")
public class Order {
}
insert into orders ...
@Entity(name = "orders")
public class Order {
}
em.createQuery("SELECT o FROM Order o")
@Entity(name = "orders")
public class Order {
}
em.createQuery("SELECT o FROM orders o")
@Entity
@Table(name = "orders")
public class Order {
}
MAPPINGS
ONE TO ONE
@Entity
public class Customer {
    @OneToOne
    private Address address;
}
@Entity
public class Address {
   ...
ONE TO ONE
@Entity
public class Customer {
    @OneToOne
    private Address address;
}
@Entity
public class Address {
   ...
ONE TO MANY
@Entity
public class Customer {
    @OneToMany
    private Set<Address> addresses;
}
ONE TO MANY
@Entity
public class Customer {
    @OneToMany
    @JoinColumn(name = "customer_id")
    private Set<Address> ...
MANY TO MANY
@Entity
public class Customer {
    @ManyToMany
    private Collection<Address> addresses;
}
@Entity
public c...
LAZY LOADING
element is loaded only when required
proxy by subclassing, but not always needed
LAZY LOADING
Custom collections
PersistentSet
PersistentBag
PersistentList
SET, BAG OR LIST?
@OneToMany
Set<Product> products;
SET, BAG OR LIST?
@OneToMany
List<Product> products;
SET, BAG OR LIST?
@OneToMany
@OrderColumn
List<Product> products;
N+1
@Entity
public class User {
    @OneToMany
    private List<Address> addresses;
}
List<User> users = em.createQuery("S...
N+1
@Entity
public class User {
    @OneToMany
    @BatchSize(size = 10)
    private List<Address> addresses;
}
N+1
SELECT DISTINCT u FROM User u
    JOIN FETCH u.addresses
HOW TO SAVE
EntityManager.persist()
EntityManager.merge()
OPTIMISTIC LOCKING
@Entity
public class User {
   @Version
   private int version;
}
OPTIMISTIC LOCKING IN REST
NEVER HEARD OF IT
IDENTITY
EQUALS() AND HASHCODE()
BASE CLASS
@MappedSuperclass
public abstract class BaseEntity implements Serializable {
    @Id @GeneratedValue
    privat...
CACHING
L1 - EntityManager cache / Session cache
L2 - EntityManagerFactory cache / SessionFactory cache
QueryCache
FLUSH MODES
MANUAL
COMMIT
AUTO
ALWAYS
LEVEL 1 CACHE PITFALLS
FLUSH() AND CLEAR()
LEVEL 2 CACHE PITFALLS
DISTRIBUTED ENVIRONMENT
HQL INJECTION
String hqlQuery = "SELECT p FROM Product p where p.category = '" + cat + "'";
List<Product> products = em.cr...
DYNAMIC UPDATES
@Entity
@DynamicUpdate
public class MyEntity {
// ...
}
DYNAMIC INSERTS
@Entity
@DynamicInsert
public class MyEntity {
// ...
}
MATERIALS
Hibernate logs analysis
Hibernate code debugging :-)
https://leanpub.com/high-performance-java-persistence
https...
QUESTIONS?
THANKS
JDD 2016 - Jakub Kubrynski - Jpa - beyond copy-paste
Upcoming SlideShare
Loading in …5
×

JDD 2016 - Jakub Kubrynski - Jpa - beyond copy-paste

128 views

Published on

JPA is the main building block in most Java projects. However, a lot of developers still use it without a deep understanding of the technology, relying mainly on applying the copy-paste methodology from StackOverflow or existing system entities. During this presentation, I will consolidate knowledge about object-relational mapping. We'll see how lazy loading works under the hood and understand the difference between a set, list or bag. We will also talk about common traps leading to significant decreases in performance or improper behaviour of the system.

Published in: Technology
  • Be the first to comment

  • Be the first to like this

JDD 2016 - Jakub Kubrynski - Jpa - beyond copy-paste

  1. 1. @jkubrynski / kubrynski.com JPA - BEYOND COPY-PASTE JAKUB KUBRYNSKI jk@devskiller.com / @jkubrynski / http://kubrynski.com
  2. 2. WHOAMI CO-FOUNDER OF DEVSKILLER TRAINER AT BOTTEGA DEVOXX.PL PROGRAM COMMITTEE CO-AUTHOR OF SPRING CLOUD CONTRACT
  3. 3. @Entity public class Product {     @Id     @GeneratedValue     private Long id;     @Column     private String name;     // ... }
  4. 4. @Entity public class Product {     @Id     @GeneratedValue     private Long id;     @Column // it does exactly nothing     private String name;     // ... }
  5. 5. @Transactional @Service public class ProductService {     public void updatePrice(Long productId, Money newPrice) {         Product product = productRepository.find(productId);         product.setPrice(newPrice);         productRepository.save(product);     } }
  6. 6. @Transactional @Service public class ProductService {     public void updatePrice(Long productId, Money newPrice) {         Product product = productRepository.find(productId);         product.setPrice(newPrice);         productRepository.save(product); // it does exactly nothing     } }
  7. 7. FIELDS VS GETTERS @Entity public class Product {     private Long id;     private String name;     @Id     public Long getId() {         return id;     } }
  8. 8. MIXED ACCESS @Entity @Access(AccessType.FIELD) public class Product {     private Long id;     private String name;     @Id     @Access(AccessType.PROPERTY)     public Long getId() {         return id;     } }
  9. 9. @Entity public class Order { }
  10. 10. @Entity(name = "orders") public class Order { }
  11. 11. @Entity(name = "orders") public class Order { } insert into orders ...
  12. 12. @Entity(name = "orders") public class Order { } em.createQuery("SELECT o FROM Order o")
  13. 13. @Entity(name = "orders") public class Order { } em.createQuery("SELECT o FROM orders o")
  14. 14. @Entity @Table(name = "orders") public class Order { }
  15. 15. MAPPINGS
  16. 16. ONE TO ONE @Entity public class Customer {     @OneToOne     private Address address; } @Entity public class Address {     @OneToOne     private Customer customer; }
  17. 17. ONE TO ONE @Entity public class Customer {     @OneToOne     private Address address; } @Entity public class Address {     @OneToOne(mappedBy = "address")     private Customer customer; }
  18. 18. ONE TO MANY @Entity public class Customer {     @OneToMany     private Set<Address> addresses; }
  19. 19. ONE TO MANY @Entity public class Customer {     @OneToMany     @JoinColumn(name = "customer_id")     private Set<Address> addresses; }
  20. 20. MANY TO MANY @Entity public class Customer {     @ManyToMany     private Collection<Address> addresses; } @Entity public class Address {     @ManyToMany     private Collection<Customer> customers; }
  21. 21. LAZY LOADING element is loaded only when required proxy by subclassing, but not always needed
  22. 22. LAZY LOADING Custom collections PersistentSet PersistentBag PersistentList
  23. 23. SET, BAG OR LIST? @OneToMany Set<Product> products;
  24. 24. SET, BAG OR LIST? @OneToMany List<Product> products;
  25. 25. SET, BAG OR LIST? @OneToMany @OrderColumn List<Product> products;
  26. 26. N+1 @Entity public class User {     @OneToMany     private List<Address> addresses; } List<User> users = em.createQuery("SELECT u FROM User u").getResultList(); for (User user : users) {     for (Address address : user.getAddresses()) {         ...     } }
  27. 27. N+1 @Entity public class User {     @OneToMany     @BatchSize(size = 10)     private List<Address> addresses; }
  28. 28. N+1 SELECT DISTINCT u FROM User u     JOIN FETCH u.addresses
  29. 29. HOW TO SAVE EntityManager.persist() EntityManager.merge()
  30. 30. OPTIMISTIC LOCKING @Entity public class User {    @Version    private int version; }
  31. 31. OPTIMISTIC LOCKING IN REST NEVER HEARD OF IT
  32. 32. IDENTITY EQUALS() AND HASHCODE()
  33. 33. BASE CLASS @MappedSuperclass public abstract class BaseEntity implements Serializable {     @Id @GeneratedValue     private Long id;     private String uuid = UUID.randomUUID().toString();     public int hashCode() {         return Objects.hash(uuid);     }     public boolean equals(Object that) {         return this == that || that instanceof BaseEntity                     && Objects.equals(uuid, ((BaseEntity) that).uuid);      } }
  34. 34. CACHING L1 - EntityManager cache / Session cache L2 - EntityManagerFactory cache / SessionFactory cache QueryCache
  35. 35. FLUSH MODES MANUAL COMMIT AUTO ALWAYS
  36. 36. LEVEL 1 CACHE PITFALLS FLUSH() AND CLEAR()
  37. 37. LEVEL 2 CACHE PITFALLS DISTRIBUTED ENVIRONMENT
  38. 38. HQL INJECTION String hqlQuery = "SELECT p FROM Product p where p.category = '" + cat + "'"; List<Product> products = em.createQuery(hqlQuery, Product.class)                            .getResultList();
  39. 39. DYNAMIC UPDATES @Entity @DynamicUpdate public class MyEntity { // ... }
  40. 40. DYNAMIC INSERTS @Entity @DynamicInsert public class MyEntity { // ... }
  41. 41. MATERIALS Hibernate logs analysis Hibernate code debugging :-) https://leanpub.com/high-performance-java-persistence https://vladmihalcea.com http://www.jooq.org
  42. 42. QUESTIONS?
  43. 43. THANKS

×