Slide 1

Slide 1 text

@jkubrynski / kubrynski.com JPA - BEYOND COPY-PASTE JAKUB KUBRYNSKI [email protected] / @jkubrynski / http://kubrynski.com

Slide 2

Slide 2 text

WHOAMI DEVSKILLER CO-FOUNDER BOTTEGA TRAINER DEVOXX.PL PROGRAM COMMITTEE SPRING CLOUD CONTRACT CO-AUTHOR

Slide 3

Slide 3 text

No content

Slide 4

Slide 4 text

ALL NON-TRIVIAL ABSTRACTIONS, TO SOME DEGREE, ARE LEAKY. JOEL SPOLSKY

Slide 5

Slide 5 text

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

Slide 6

Slide 6 text

@Entity public class Product { @Id @GeneratedValue private Long id; @Column // it does exactly nothing private String name; // ... }

Slide 7

Slide 7 text

@Transactional @Service public class ProductService { public void updatePrice(Long productId, Money newPrice) { Product product = productRepository.find(productId); product.setPrice(newPrice); productRepository.save(product); } }

Slide 8

Slide 8 text

@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 } }

Slide 9

Slide 9 text

FIELDS VS GETTERS @Entity public class Product { private Long id; private String name; @Id public Long getId() { return id; } }

Slide 10

Slide 10 text

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

Slide 11

Slide 11 text

@Entity public class Order { }

Slide 12

Slide 12 text

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

Slide 13

Slide 13 text

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

Slide 14

Slide 14 text

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

Slide 15

Slide 15 text

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

Slide 16

Slide 16 text

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

Slide 17

Slide 17 text

MAPPINGS

Slide 18

Slide 18 text

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

Slide 19

Slide 19 text

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

Slide 20

Slide 20 text

ONE TO MANY @Entity public class Customer { @OneToMany private Set
addresses; }

Slide 21

Slide 21 text

ONE TO MANY @Entity public class Customer { @OneToMany @JoinColumn(name = "customer_id") private Set
addresses; }

Slide 22

Slide 22 text

MANY TO MANY @Entity public class Customer { @ManyToMany private Collection
addresses; } @Entity public class Address { @ManyToMany private Collection customers; }

Slide 23

Slide 23 text

LAZY LOADING element is loaded only when required proxy by subclassing, but not always needed

Slide 24

Slide 24 text

LAZY LOADING Custom collections PersistentSet PersistentBag PersistentList

Slide 25

Slide 25 text

SET, BAG OR LIST? @OneToMany Set products;

Slide 26

Slide 26 text

SET, BAG OR LIST? @OneToMany List products;

Slide 27

Slide 27 text

SET, BAG OR LIST? @OneToMany @OrderColumn List products;

Slide 28

Slide 28 text

N+1 @Entity public class User { @OneToMany private List
addresses; } List users = em.createQuery("SELECT u FROM User u").getResultList(); for (User user : users) { for (Address address : user.getAddresses()) { ... } }

Slide 29

Slide 29 text

N+1 @Entity public class User { @OneToMany @BatchSize(size = 10) private List
addresses; }

Slide 30

Slide 30 text

N+1 SELECT DISTINCT u FROM User u JOIN FETCH u.addresses

Slide 31

Slide 31 text

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

Slide 32

Slide 32 text

OPTIMISTIC LOCKING @Entity public class User { @Version private int version; }

Slide 33

Slide 33 text

OPTIMISTIC LOCKING IN REST NEVER HEARD OF IT

Slide 34

Slide 34 text

IDENTITY EQUALS() AND HASHCODE()

Slide 35

Slide 35 text

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); }

Slide 36

Slide 36 text

CACHING L1 - EntityManager cache / Session cache L2 - EntityManagerFactory cache / SessionFactory cache QueryCache

Slide 37

Slide 37 text

FLUSH MODES MANUAL COMMIT AUTO ALWAYS

Slide 38

Slide 38 text

LEVEL 1 CACHE PITFALLS FLUSH() AND CLEAR()

Slide 39

Slide 39 text

LEVEL 2 CACHE PITFALLS DISTRIBUTED ENVIRONMENT

Slide 40

Slide 40 text

HQL INJECTION String hqlQuery = "SELECT p FROM Product p where p.category = '" + cat + "'"; List products = em.createQuery(hqlQuery, Product.class) .getResultList();

Slide 41

Slide 41 text

MATERIALS Hibernate logs analysis Hibernate code debugging :-) https://leanpub.com/high-performance-java- persistence https://vladmihalcea.com http://www.jooq.org

Slide 42

Slide 42 text

QUESTIONS?

Slide 43

Slide 43 text

THANKS

Slide 44

Slide 44 text

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

Slide 45

Slide 45 text

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