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 / CODEARTE
TRAINER AT BOTTEGA
DEVOXX.PL PROGRAM COMMITTEE
FORMER CONFITURA.PL
@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 g...
MIXED ACCESS
@Entity
@Access(AccessType.FIELD) 
public class Product {
    private Long id; 
    private String name; 
   ...
@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 {
}
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<Addres...
MANY TO MANY
@Entity
public class Customer { 
    @ManyToMany 
    private Collection<Address> addresses; 
}
@Entity
publi...
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(...
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 
    pri...
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.c...
DYNAMIC UPDATES
@Entity
@DynamicUpdate 
public class MyEntity { 
// ...
}
DYNAMIC INSERTS
@Entity
@DynamicInsert 
public class MyEntity { 
// ...
}
QUESTIONS?
THANKS
JPA - Beyond copy-paste
Upcoming SlideShare
Loading in …5
×

JPA - Beyond copy-paste

1,421 views

Published on

Slides from my talk

Published in: Software
  • Be the first to comment

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 / CODEARTE TRAINER AT BOTTEGA DEVOXX.PL PROGRAM COMMITTEE FORMER CONFITURA.PL
  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. ONE TO ONE @Entity public class Customer {      @OneToOne      private Address address;  } @Entity public class Address {     @OneToOne      private Customer customer;  }
  16. 16. ONE TO ONE @Entity public class Customer {      @OneToOne      private Address address;  } @Entity public class Address {     @OneToOne(mappedBy = "address")      private Customer customer;  }
  17. 17. ONE TO MANY @Entity public class Customer {      @OneToMany      private Set<Address> addresses;  }
  18. 18. ONE TO MANY @Entity public class Customer {      @OneToMany      @JoinColumn(name = "customer_id")      private Set<Address> addresses;  }
  19. 19. MANY TO MANY @Entity public class Customer {      @ManyToMany      private Collection<Address> addresses;  } @Entity public class Address {     @ManyToMany      private Collection<Customer> customers;  }
  20. 20. LAZY LOADING element is loaded only when required proxy by subclassing, but not always needed
  21. 21. LAZY LOADING Custom collections PersistentSet PersistentBag PersistentList
  22. 22. SET, BAG OR LIST? @OneToMany  Set<Product> products; 
  23. 23. SET, BAG OR LIST? @OneToMany  List<Product> products; 
  24. 24. SET, BAG OR LIST? @OneToMany  @OrderColumn  List<Product> products; 
  25. 25. 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()) {          ...      } }
  26. 26. N+1 @Entity public class User {     @OneToMany      @BatchSize(size = 10)      private List<Address> addresses;  }
  27. 27. N+1 SELECT DISTINCT u FROM User u      JOIN FETCH u.addresses 
  28. 28. HOW TO SAVE EntityManager.persist() EntityManager.merge()
  29. 29. OPTIMISTIC LOCKING @Entity public class User {    @Version     private int version;  }
  30. 30. OPTIMISTIC LOCKING IN REST NEVER HEARD OF IT
  31. 31. IDENTITY EQUALS() AND HASHCODE()
  32. 32. 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);       } }
  33. 33. CACHING L1 - EntityManager cache / Session cache L2 - EntityManagerFactory cache / SessionFactory cache QueryCache
  34. 34. FLUSH MODES MANUAL COMMIT AUTO ALWAYS
  35. 35. LEVEL 1 CACHE PITFALLS FLUSH() AND CLEAR()
  36. 36. LEVEL 2 CACHE PITFALLS DISTRIBUTED ENVIRONMENT
  37. 37. HQL INJECTION String hqlQuery = "SELECT p FROM Product p where p.category = '" + cat + "'";  List<Product> products = em.createQuery(hqlQuery, Product.class)                             .getResultList(); 
  38. 38. DYNAMIC UPDATES @Entity @DynamicUpdate  public class MyEntity {  // ... }
  39. 39. DYNAMIC INSERTS @Entity @DynamicInsert  public class MyEntity {  // ... }
  40. 40. QUESTIONS?
  41. 41. THANKS

×