21
PERFORMANTE JAVA ENTERPRISE APPLIKATIONEN TROTZ O/R-MAPPING Simon Martinelli, simas GmbH @simas_ch | about.me/simas_ch https://github.com/simasch/orders

Performante Java Enterprise Applikationen trotz O/R-Mapping

Embed Size (px)

Citation preview

Page 1: Performante Java Enterprise Applikationen trotz O/R-Mapping

PERFORMANTE JAVA ENTERPRISE APPLIKATIONENTROTZ O/R-MAPPING

Simon Martinelli, simas GmbH@simas_ch | about.me/simas_ch

https://github.com/simasch/orders

Page 2: Performante Java Enterprise Applikationen trotz O/R-Mapping

DAS PROBLEM

Page 3: Performante Java Enterprise Applikationen trotz O/R-Mapping

DAS MODELL

Page 4: Performante Java Enterprise Applikationen trotz O/R-Mapping

N+1 SELECT PROBLEM• Orders und OrderItems =

FetchType.LAZY@OneToMany(mappedBy = "customer", cascade = CascadeType.ALL, orphanRemoval = true)private Set<Order> orders;

@OneToMany(mappedBy = "order", cascade = CascadeType.ALL, orphanRemoval = true)private List<OrderItem> items;

• Ein Query für alle Customers• Pro Customer 1 Query für die Orders• Pro Order 1 Query für die OrderItems

Page 5: Performante Java Enterprise Applikationen trotz O/R-Mapping

LÖSUNGSANSÄTZE• FetchType.EAGER oder EntityGraph

(JPA 2.1)– Nur ein Hinweis für JPA – != SQL JOIN– Hibernate erlaubt nur eine List mit

FetchType.EAGER pro Entityorg.hibernate.HibernateException: cannot simultaneously fetch multiple bags

• JOIN FETCH– Achtung vor kartesischen Produkten

Page 6: Performante Java Enterprise Applikationen trotz O/R-Mapping

DTO

Quelle: Martin Fowler, http://martinfowler.com/eaaCatalog/dataTransferObject.html

Page 7: Performante Java Enterprise Applikationen trotz O/R-Mapping

CustomerInfoDTOpublic class CustomerInfoDTO {

private final Long id; private final String lastname; private final String firstname; private final double revenue;

public CustomerInfoDTO(Long id, String lastname, String firstname, double revenue) { this.id = id; this.lastname = lastname; this.firstname = firstname; this.revenue = revenue; }...

Page 8: Performante Java Enterprise Applikationen trotz O/R-Mapping

CONSTRUCTOR EXPRESSIONQuery q = em.createQuery(

"SELECT " + "NEW control.CustomerInfoDTO(c.id, c.lastname, c.firstname," +

"SUM(i.product.price)) " + "FROM Customer c " + "JOIN c.orders o " + "JOIN o.items i " + "GROUP BY c.lastnamem, c.firstname" +

"ORDER BY c.lastname, c.firstname");

List<CustomerInfoDTO> list = q.getResultList();

Page 9: Performante Java Enterprise Applikationen trotz O/R-Mapping

DAS DATENMODELL IM ZENTRUM

• Ein 1-1 Abbild der Datenbank in Entities oft unnötig

X

Page 10: Performante Java Enterprise Applikationen trotz O/R-Mapping

WAS IST MIT JPQL OHNE DIE BEZIEHUNG CUSTOMER->ORDER?

NEU IN JPA 2.1

Query q = em.createQuery("SELECT " +

"NEW control.CustomerInfoDTO(c.id, c.lastname, c.firstname, " +

"SUM(i.product.price)) " + "FROM Customer c " + "JOIN c.orders o ON o.customerId = c.id " + "JOIN o.items i " +

"GROUP BY c.lastname, c.firstname" +"ORDER BY c.lastname, c.firstname");

List<CustomerInfoDTO> list = q.getResultList();

Page 11: Performante Java Enterprise Applikationen trotz O/R-Mapping

ORM FÜR ALLES?Just because you're using Hibernate, doesn't mean you have to use it for everything.

A point I've been making for about ten years now.

Gavin King, 10.12.2013

Page 12: Performante Java Enterprise Applikationen trotz O/R-Mapping

SQL?• VORTEILE– Testbar mit SQL Developer/TOAD/IDE– Optimierbar (Execution Plan)

• ABER SQL VON HAND? NEIN!– JPA 2.1 ConstructorResult– QLRM– jOOQ

Page 13: Performante Java Enterprise Applikationen trotz O/R-Mapping

JPA 2.1 CONSTRUCTOR RESULT

Query q = em.createNativeQuery( "SELECT C.ID, C.LASTNAME, C.FIRSTNAME, SUM(P.PRICE) AS REVENUE" +

"FROM CUSTOMERS C " + "JOIN ORDERS O ON O.CUSTOMER_ID = C.ID " + "JOIN ORDERITEMS I ON I.ORDER_ID = O.ID " +"JOIN PRODUCTS P ON P.ID = I.PRODUCT_ID " +"GROUP BY C.ID, C.LASTNAME, C.FIRSTNAME " +"ORDER BY C.LASTNAME, C.FIRSTNAME", "CustomerInfoDTO");

@SqlResultSetMapping(name="CustomerInfoDTO", classes={ @ConstructorResult(targetClass=CustomerInfoDTO.class, columns={@ColumnResult(name="ID"), @ColumnResult(name="LASTNAME"), @ColumnResult(name="FIRSTNAME"), @ColumnResult(name="REVENUE", type=Double.class)}) })

Page 14: Performante Java Enterprise Applikationen trotz O/R-Mapping

QLRMQuery q = em.createNativeQuery( "SELECT C.ID, C.LASTNAME, C.FIRSTNAME, SUM(P.PRICE) AS REVENUE" +

"FROM CUSTOMERS C " + "JOIN ORDERS O ON O.CUSTOMER_ID = C.ID " + "JOIN ORDERITEMS I ON I.ORDER_ID = O.ID " +"JOIN PRODUCTS P ON P.ID = I.PRODUCT_ID " +"GROUP BY C.ID, C.LASTNAME, C.FIRSTNAME " +"ORDER BY C.LASTNAME, C.FIRSTNAME");

JpaResultMapper mapper = new JpaResultMapper();

List<CustomerInfoDTO> list = jpaResultMapper.list(q,

CustomerInfoDTO.class);

QLRM: https://github.com/simasch/qlrm

Page 15: Performante Java Enterprise Applikationen trotz O/R-Mapping

jOOQList<CustomersInfoDTO> list = create. select(CUSTOMERS.ID, CUSTOMERS.LASTNAME, CUSTOMERS.FIRSTNAME,

sum(PRODUCTS.PRICE)). from(CUSTOMERS). join(ORDERS).on(ORDERS.CUSTOMER_ID.eq(CUSTOMERS.ID)). join(ORDERITEMS).on(ORDERITEMS.ORDER_ID.eq(ORDERS.ID)). join(PRODUCTS).on(PRODUCTS.ID.eq(ORDERITEMS.PRODUCT_ID)). groupBy(CUSTOMERS.ID, CUSTOMERS.NAME).

orderBy(CUSTOMERS.NAME). fetchInto(CustomersInfoDTO.class);

jOOQ: http://www.jooq.org

Page 16: Performante Java Enterprise Applikationen trotz O/R-Mapping

CQRS

Quelle: Martin Fowler, http://martinfowler.com/bliki/CQRS.html

Page 17: Performante Java Enterprise Applikationen trotz O/R-Mapping

CQRS IM KLEINEN• QUERIES– JPA Constructor Expression– JPA ConstructorResult– QLRM– jOOQ

• COMMANDS– JPA Entities

Page 18: Performante Java Enterprise Applikationen trotz O/R-Mapping

EMPFEHLUNGEN• Entities zum Erstellen und Ändern

der Daten

• DTO für lesende Zugriffe– Constructor Expression– SQL mit QLRM oder jOOQ

Page 19: Performante Java Enterprise Applikationen trotz O/R-Mapping

BONUS MATERIAL

Page 20: Performante Java Enterprise Applikationen trotz O/R-Mapping

RANDOM-DATA-GENERATORRandomDataGenerator randomDataGenerator = new RandomDataGenerator();

List<Customer> customers = randomDataGenerator.generateList(400,new GenConfig()

.name(Name.Firstname, "firstname") .name(Name.Lastname, "lastname"),

Customer.class);

Page 21: Performante Java Enterprise Applikationen trotz O/R-Mapping

LOG4JDBC

log4jdbc-log4j2: https://code.google.com/p/log4jdbc-log4j2/

Anpassungen im META-INF/persistence.xml

<property name="javax.persistence.jdbc.url"

value="jdbc:log4jdbc:derby://localhost:1527/orders"/>

<property name="javax.persistence.jdbc.driver" value="net.sf.log4jdbc.sql.jdbcapi.DriverSpy"/>