JPA - Beyond Copy-Paste

JPA - Beyond Copy-Paste

13962ee99d2c07e7b7a7776222532f1d?s=128

Jakub Kubryński

May 19, 2017
Tweet

Transcript

  1. @jkubrynski / kubrynski.com JPA - BEYOND COPY-PASTE JAKUB KUBRYNSKI jk@devskiller.com

    / @jkubrynski / http://kubrynski.com
  2. WHOAMI DEVSKILLER CO-FOUNDER BOTTEGA TRAINER DEVOXX.PL PROGRAM COMMITTEE SPRING CLOUD

    CONTRACT CO-AUTHOR
  3. None
  4. ALL NON-TRIVIAL ABSTRACTIONS, TO SOME DEGREE, ARE LEAKY. JOEL SPOLSKY

  5. @Entity public class Product { @Id @GeneratedValue private Long id;

    @Column private String name; // ... }
  6. @Entity public class Product { @Id @GeneratedValue private Long id;

    @Column // it does exactly nothing private String name; // ... }
  7. @Transactional @Service public class ProductService { public void updatePrice(Long productId,

    Money newPrice) { Product product = productRepository.find(productId); product.setPrice(newPrice); productRepository.save(product); } }
  8. @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 } }
  9. FIELDS VS GETTERS @Entity public class Product { private Long

    id; private String name; @Id public Long getId() { return id; } }
  10. MIXED ACCESS @Entity @Access(AccessType.FIELD) public class Product { private Long

    id; private String name; @Id @Access(AccessType.PROPERTY) public Long getId() { return id; } }
  11. @Entity public class Order { }

  12. @Entity(name = "orders") public class Order { }

  13. @Entity(name = "orders") public class Order { } insert into

    orders ...
  14. @Entity(name = "orders") public class Order { } em.createQuery("SELECT o

    FROM Order o")
  15. @Entity(name = "orders") public class Order { } em.createQuery("SELECT o

    FROM orders o")
  16. @Entity @Table(name = "orders") public class Order { }

  17. MAPPINGS

  18. ONE TO ONE @Entity public class Customer { @OneToOne private

    Address address; } @Entity public class Address { @OneToOne private Customer customer; }
  19. ONE TO ONE @Entity public class Customer { @OneToOne private

    Address address; } @Entity public class Address { @OneToOne(mappedBy = "address") private Customer customer; }
  20. ONE TO MANY @Entity public class Customer { @OneToMany private

    Set<Address> addresses; }
  21. ONE TO MANY @Entity public class Customer { @OneToMany @JoinColumn(name

    = "customer_id") private Set<Address> addresses; }
  22. MANY TO MANY @Entity public class Customer { @ManyToMany private

    Collection<Address> addresses; } @Entity public class Address { @ManyToMany private Collection<Customer> customers; }
  23. LAZY LOADING element is loaded only when required proxy by

    subclassing, but not always needed
  24. LAZY LOADING Custom collections PersistentSet PersistentBag PersistentList

  25. SET, BAG OR LIST? @OneToMany Set<Product> products;

  26. SET, BAG OR LIST? @OneToMany List<Product> products;

  27. SET, BAG OR LIST? @OneToMany @OrderColumn List<Product> products;

  28. 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()) { ... } }
  29. N+1 @Entity public class User { @OneToMany @BatchSize(size = 10)

    private List<Address> addresses; }
  30. N+1 SELECT DISTINCT u FROM User u JOIN FETCH u.addresses

  31. HOW TO SAVE EntityManager.persist() EntityManager.merge()

  32. OPTIMISTIC LOCKING @Entity public class User { @Version private int

    version; }
  33. OPTIMISTIC LOCKING IN REST NEVER HEARD OF IT

  34. IDENTITY EQUALS() AND HASHCODE()

  35. 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); }
  36. CACHING L1 - EntityManager cache / Session cache L2 -

    EntityManagerFactory cache / SessionFactory cache QueryCache
  37. FLUSH MODES MANUAL COMMIT AUTO ALWAYS

  38. LEVEL 1 CACHE PITFALLS FLUSH() AND CLEAR()

  39. LEVEL 2 CACHE PITFALLS DISTRIBUTED ENVIRONMENT

  40. HQL INJECTION String hqlQuery = "SELECT p FROM Product p

    where p.category = '" + cat + "'"; List<Product> products = em.createQuery(hqlQuery, Product.class) .getResultList();
  41. MATERIALS Hibernate logs analysis Hibernate code debugging :-) https://leanpub.com/high-performance-java- persistence

    https://vladmihalcea.com http://www.jooq.org
  42. QUESTIONS?

  43. THANKS

  44. DYNAMIC UPDATES @Entity @DynamicUpdate public class MyEntity { // ...

    }
  45. DYNAMIC INSERTS @Entity @DynamicInsert public class MyEntity { // ...

    }