92
Copyright © 2014 Oracle and/or its affiliates. All rights reserved. | Thinking Beyond ORM in JPA Patrycja Wegrzynowicz CTO Yonita, Inc. March 15, 2016 Please Stand By. This session will begin p indicated on the agenda. Thank You.

Thinking Beyond ORM in JPA

Embed Size (px)

Citation preview

Page 1: Thinking Beyond ORM in JPA

Copyright © 2014 Oracle and/or its affiliates. All rights reserved. |

Thinking Beyond ORM in JPAPatrycja WegrzynowiczCTOYonita, Inc.March 15, 2016

Please Stand By. This session will begin promptly at the time indicated on the agenda. Thank You.

Page 2: Thinking Beyond ORM in JPA

Copyright © 2014 Oracle and/or its affiliates. All rights reserved. |

Safe Harbor StatementThe following is intended to outline our general product direction. It is intended for information purposes only, and may not be incorporated into any contract. It is not a commitment to deliver any material, code, or functionality, and should not be relied upon in making purchasing decisions. The development, release, and timing of any features or functionality described for Oracle’s products remains at the sole discretion of Oracle.

2

Page 3: Thinking Beyond ORM in JPA

Copyright © 2014 Oracle and/or its affiliates. All rights reserved. |

About Me• 15+ professional experience – Still an active developer!

• Author and speaker – JavaOne, Devoxx, JavaZone, others

• Finalizing PhD in Computer Science• Founder and CTO of Yonita – Consulting plus automated tools for

detection of bugs in software– Security, performance, databases

• Twitter @yonlabs Oracle Confidential – Internal/Restricted/Highly Restricted

3

Page 4: Thinking Beyond ORM in JPA

Copyright © 2014 Oracle and/or its affiliates. All rights reserved. |

Outline• Why?– App-centric vs. data-centric

• What?–Use cases and performance

• How?– JPA (2.1)

Page 5: Thinking Beyond ORM in JPA

Copyright © 2014 Oracle and/or its affiliates. All rights reserved. |

Database

Page 6: Thinking Beyond ORM in JPA

Copyright © 2014 Oracle and/or its affiliates. All rights reserved. |

Database – The Mordor of Java Developers

Page 7: Thinking Beyond ORM in JPA

Copyright © 2014 Oracle and/or its affiliates. All rights reserved. |

Why? Different paradigms!• One size doesn’t fit all!• App-centric– Java code drives database design–One app accesses data– CRUD more often than complex

queries

• Data-centric– Database design drives Java code– Several apps access data– CRUD as often as complex queries

Page 8: Thinking Beyond ORM in JPA

Copyright © 2014 Oracle and/or its affiliates. All rights reserved. |

What? Use Cases

Legacy systemsReportingComplex queriesBulk operations

Page 9: Thinking Beyond ORM in JPA

Copyright © 2014 Oracle and/or its affiliates. All rights reserved. |

What? Performance

SpeedLatencyThroughput

Page 10: Thinking Beyond ORM in JPA

Copyright © 2014 Oracle and/or its affiliates. All rights reserved. |

Legacy Systems

Page 11: Thinking Beyond ORM in JPA

Copyright © 2014 Oracle and/or its affiliates. All rights reserved. |

Legacy systems and Database-Level Abstraction• Legacy systems– It’s always worked that way!– Database was all we had!–We need to feed all those apps!

• Abstraction– Views– Stored procedures– Triggers

Page 12: Thinking Beyond ORM in JPA

Copyright © 2014 Oracle and/or its affiliates. All rights reserved. |

Stored Procedures in JPA• 2.0 and before–Native queries to call stored procedures–No OUT/INOUT parameters– Database dependent CALL syntax

• 2.1– EntityManager.createStoredProcedureQuery–@NamedStoredProcedureQuery

Page 13: Thinking Beyond ORM in JPA

Copyright © 2014 Oracle and/or its affiliates. All rights reserved. |

Example: Stored ProcedureResult Set-- MySQLCREATE PROCEDURE GET_EMPLOYEES()BEGIN

SELECT * FROM EMPLOYEES;END

Page 14: Thinking Beyond ORM in JPA

Copyright © 2014 Oracle and/or its affiliates. All rights reserved. |

Example: Stored ProcedureEntityManager API// create and setup a stored procedure queryStoredProcedureQuery q = em.createStoredProcedureQuery("GET_EMPLOYEES", Employee.class);

// gather the resultsList<Employee> list = (List<Employee>) q.getResultList();

Page 15: Thinking Beyond ORM in JPA

Copyright © 2014 Oracle and/or its affiliates. All rights reserved. |

Example: Stored ProcedureEntityManager API// create and setup a stored procedure queryStoredProcedureQuery q = em.createStoredProcedureQuery("GET_EMPLOYEES", Employee.class);

// gather the resultsList<Employee> list = (List<Employee>) q.getResultList();

Page 16: Thinking Beyond ORM in JPA

Copyright © 2014 Oracle and/or its affiliates. All rights reserved. |

Example: Stored ProcedureEntityManager API// create and setup a stored procedure queryStoredProcedureQuery q = em.createStoredProcedureQuery("GET_EMPLOYEES", Employee.class);

// gather the resultsList<Employee> list = (List<Employee>) q.getResultList();

Page 17: Thinking Beyond ORM in JPA

Copyright © 2014 Oracle and/or its affiliates. All rights reserved. |

Example: Stored ProcedureEntityManager API// create and setup a stored procedure queryStoredProcedureQuery q = em.createStoredProcedureQuery("GET_EMPLOYEES", Employee.class);

// gather the results, an implicit call to an execute method!List<Employee> list = (List<Employee>) q.getResultList();

Page 18: Thinking Beyond ORM in JPA

Copyright © 2014 Oracle and/or its affiliates. All rights reserved. |

Example: Stored ProcedureOUT Parameter-- MySQLCREATE PROCEDURE SUM_SALARIES(OUT TOTAL INT)BEGIN

SELECT SUM(SALARY) INTO TOTALFROM EMPLOYEES;

END

Page 19: Thinking Beyond ORM in JPA

Copyright © 2014 Oracle and/or its affiliates. All rights reserved. |

Example: Stored ProcedureEntityManager API// create and setup a stored procedure queryStoredProcedureQuery q = em.createStoredProcedureQuery("SUM_SALARIES");q.registerStoredProcedureParameter("TOTAL", Integer.class, ParameterMode.OUT);

// execute the query...q.execute();

// ...to obtain the output valueInteger total = (Integer) q.getOutputParameterValue("TOTAL");

Page 20: Thinking Beyond ORM in JPA

Copyright © 2014 Oracle and/or its affiliates. All rights reserved. |

Example: Stored ProcedureEntityManager API// create and setup a stored procedure queryStoredProcedureQuery q = em.createStoredProcedureQuery("SUM_SALARIES");q.registerStoredProcedureParameter("TOTAL", Integer.class, ParameterMode.OUT);

// execute the query...q.execute();

// ...to obtain the output valueInteger total = (Integer) q.getOutputParameterValue("TOTAL");

Page 21: Thinking Beyond ORM in JPA

Copyright © 2014 Oracle and/or its affiliates. All rights reserved. |

Example: Stored ProcedureEntityManager API// create and setup a stored procedure queryStoredProcedureQuery q = em.createStoredProcedureQuery("SUM_SALARIES");q.registerStoredProcedureParameter("TOTAL", Integer.class, ParameterMode.OUT);

// execute the query...q.execute();

// ...to obtain the output valueInteger total = (Integer) q.getOutputParameterValue("TOTAL");

Page 22: Thinking Beyond ORM in JPA

Copyright © 2014 Oracle and/or its affiliates. All rights reserved. |

Example: Stored ProcedureEntityManager API// create and setup a stored procedure queryStoredProcedureQuery q = em.createStoredProcedureQuery("SUM_SALARIES");q.registerStoredProcedureParameter("TOTAL", Integer.class, ParameterMode.OUT);

// execute the query...q.execute();

// ...to obtain the output valueInteger total = (Integer) q.getOutputParameterValue("TOTAL");

Page 23: Thinking Beyond ORM in JPA

Copyright © 2014 Oracle and/or its affiliates. All rights reserved. |

Example: Stored ProcedureAll in One-- MySQLCREATE PROCEDURE GET_EMPLOYEES(

IN GIVEN_COUNTRY VARCHAR(255), OUT TOTAL INT

)BEGIN

SELECT SUM(SALARY) INTO TOTALFROM EMPLOYEESWHERE COUNTRY = GIVEN_COUNTRY; SELECT *FROM EMPLOYEESWHERE COUNTRY = GIVEN_COUNTRY;

END

Page 24: Thinking Beyond ORM in JPA

Copyright © 2014 Oracle and/or its affiliates. All rights reserved. |

Example: Stored ProcedureEntityManager API// create and setup a stored procedure queryStoredProcedureQuery q = em.createStoredProcedureQuery("GET_EMPLOYEES", Employee.class);q.registerStoredProcedureParameter("COUNTRY", String.class, ParameterMode.IN);q.registerStoredProcedureParameter("TOTAL", Integer.class, ParameterMode.OUT);

// setup the parametersq.setParameter("COUNTRY", "Poland");

// obtain the employees...List<Employee> list = (List<Employee>) q.getResultList();

// ...and the output valueInteger total = (Integer) q.getOutputParameterValue("TOTAL");

Page 25: Thinking Beyond ORM in JPA

Copyright © 2014 Oracle and/or its affiliates. All rights reserved. |

Example: Stored ProcedureEntityManager API// create and setup a stored procedure queryStoredProcedureQuery q = em.createStoredProcedureQuery("GET_EMPLOYEES", Employee.class);q.registerStoredProcedureParameter("COUNTRY", String.class, ParameterMode.IN);q.registerStoredProcedureParameter("TOTAL", Integer.class, ParameterMode.OUT);

// setup the parametersq.setParameter("COUNTRY", "Poland");

// obtain the employees...List<Employee> list = (List<Employee>) q.getResultList();

// ...and the output valueInteger total = (Integer) q.getOutputParameterValue("TOTAL");

Page 26: Thinking Beyond ORM in JPA

Copyright © 2014 Oracle and/or its affiliates. All rights reserved. |

Example: Stored ProcedureEntityManager API// create and setup a stored procedure queryStoredProcedureQuery q = em.createStoredProcedureQuery("GET_EMPLOYEES", Employee.class);q.registerStoredProcedureParameter("COUNTRY", String.class, ParameterMode.IN);q.registerStoredProcedureParameter("TOTAL", Integer.class, ParameterMode.OUT);

// setup the parametersq.setParameter("COUNTRY", "Poland");

// obtain the employees...List<Employee> list = (List<Employee>) q.getResultList();

// ...and the output valueInteger total = (Integer) q.getOutputParameterValue("TOTAL");

Page 27: Thinking Beyond ORM in JPA

Copyright © 2014 Oracle and/or its affiliates. All rights reserved. |

Example: Stored ProcedureEntityManager API// create and setup a stored procedure queryStoredProcedureQuery q = em.createStoredProcedureQuery("GET_EMPLOYEES", Employee.class);q.registerStoredProcedureParameter("COUNTRY", String.class, ParameterMode.IN);q.registerStoredProcedureParameter("TOTAL", Integer.class, ParameterMode.OUT);

// setup the parametersq.setParameter("COUNTRY", "Poland");

// obtain the employees...List<Employee> list = (List<Employee>) q.getResultList();

// ...and the output valueInteger total = (Integer) q.getOutputParameterValue("TOTAL");

Page 28: Thinking Beyond ORM in JPA

Copyright © 2014 Oracle and/or its affiliates. All rights reserved. |

Example: Stored ProcedureEntityManager API// create and setup a stored procedure queryStoredProcedureQuery q = em.createStoredProcedureQuery("GET_EMPLOYEES", Employee.class);q.registerStoredProcedureParameter("COUNTRY", String.class, ParameterMode.IN);q.registerStoredProcedureParameter("TOTAL", Integer.class, ParameterMode.OUT);

// setup the parametersq.setParameter("COUNTRY", "Poland");

// obtain the employees...List<Employee> list = (List<Employee>) q.getResultList();

// ...and the output valueInteger total = (Integer) q.getOutputParameterValue("TOTAL");

Page 29: Thinking Beyond ORM in JPA

Copyright © 2014 Oracle and/or its affiliates. All rights reserved. |

Example: Stored ProcedureEntityManager API// create and setup a stored procedure queryStoredProcedureQuery q = em.createStoredProcedureQuery("GET_EMPLOYEES",Employee.class); q.registerStoredProcedureParameter("TOTAL", Integer.class, ParameterMode.OUT);

// setup the parametersq.setParameter("COUNTRY", "Poland");

// obtain the employeesList<Employee> list = (List<Employee>) q.getResultList();

// do we need the execute call here?Integer total = (Integer) q.getOutputParameterValue("TOTAL");

Page 30: Thinking Beyond ORM in JPA

Copyright © 2014 Oracle and/or its affiliates. All rights reserved. |

Example: Stored ProcedureEntityManager API// create and setup a stored procedure queryStoredProcedureQuery q = em.createStoredProcedureQuery("GET_EMPLOYEES", Employee.class);q.registerStoredProcedureParameter("COUNTRY", String.class, ParameterMode.IN);q.registerStoredProcedureParameter("TOTAL", Integer.class, ParameterMode.OUT);

// setup the parametersq.setParameter("COUNTRY", "Poland");

// first, an implicit call to executeList<Employee> list = (List<Employee>) q.getResultList();

// ...then, we can safely obtain the output value Integer total = (Integer) q.getOutputParameterValue("TOTAL");

Page 31: Thinking Beyond ORM in JPA

Copyright © 2014 Oracle and/or its affiliates. All rights reserved. |

Example: Stored ProcedureEntityManager API// create and setup a stored procedure queryStoredProcedureQuery q = em.createStoredProcedureQuery("GET_EMPLOYEES", Employee.class);q.registerStoredProcedureParameter("COUNTRY", String.class, ParameterMode.IN);q.registerStoredProcedureParameter("TOTAL", Integer.class, ParameterMode.OUT);

// setup the parametersq.setParameter("COUNTRY", "Poland");

// what if we reorder the lines?Integer total = (Integer) q.getOutputParameterValue("TOTAL");List<Employee> list = (List<Employee>) q.getResultList();

Page 32: Thinking Beyond ORM in JPA

Copyright © 2014 Oracle and/or its affiliates. All rights reserved. |

Example: Stored ProcedureEntityManager API// create and setup a stored procedure queryStoredProcedureQuery q = em.createStoredProcedureQuery("GET_EMPLOYEES", Employee.class);q.registerStoredProcedureParameter("COUNTRY", String.class, ParameterMode.IN);q.registerStoredProcedureParameter("TOTAL", Integer.class, ParameterMode.OUT);

// setup the parametersq.setParameter("COUNTRY", "Poland");

// what if we reorder the lines?Integer total = (Integer) q.getOutputParameterValue("TOTAL");

// an implicit call to executeList<Employee> list = (List<Employee>) q.getResultList();

Page 33: Thinking Beyond ORM in JPA

Copyright © 2014 Oracle and/or its affiliates. All rights reserved. |

Example: Stored ProcedureEntityManager API// create and setup a stored procedure queryq = em.createStoredProcedureQuery("GET_EMPLOYEES", Employee.class);q.registerStoredProcedureParameter("COUNTRY", String.class, ParameterMode.IN);q.registerStoredProcedureParameter("TOTAL", Integer.class, ParameterMode.OUT);

// setup the parametersq.setParameter("COUNTRY", "Poland");

// execute must be called before getOutputParameterValueq.execute();

Integer total = (Integer) q.getOutputParameterValue("TOTAL");List<Employee> list = (List<Employee>) q.getResultList();

Page 34: Thinking Beyond ORM in JPA

Copyright © 2014 Oracle and/or its affiliates. All rights reserved. |

Example: Stored ProcedureEntityManager API// create and setup a stored procedure queryq = em.createStoredProcedureQuery("GET_EMPLOYEES", Employee.class);q.registerStoredProcedureParameter("COUNTRY", String.class, ParameterMode.IN);q.registerStoredProcedureParameter("TOTAL", Integer.class, ParameterMode.OUT);

// setup the parametersq.setParameter("COUNTRY", "Poland");

// execute must be called before getOutputParameterValueq.execute();

Integer total = (Integer) q.getOutputParameterValue("TOTAL");// does it call execute once more?List<Employee> list = (List<Employee>) q.getResultList();

Page 35: Thinking Beyond ORM in JPA

Copyright © 2014 Oracle and/or its affiliates. All rights reserved. |

Example: Stored ProcedureEntityManager API// create and setup a stored procedure queryq = em.createStoredProcedureQuery("GET_EMPLOYEES", Employee.class);q.registerStoredProcedureParameter("COUNTRY", String.class, ParameterMode.IN);q.registerStoredProcedureParameter("TOTAL", Integer.class, ParameterMode.OUT);

// setup the parametersq.setParameter("COUNTRY", "Poland");

// execute must be called before getOutputParameterValueq.execute();

Integer total = (Integer) q.getOutputParameterValue("TOTAL");// an implicit call to execute only if not executed yet!List<Employee> list = (List<Employee>) q.getResultList();

Page 36: Thinking Beyond ORM in JPA

Copyright © 2014 Oracle and/or its affiliates. All rights reserved. |

Example: Stored ProcedureEntityManager API// create and setup a stored procedure queryq = em.createStoredProcedureQuery("GET_EMPLOYEES", Employee.class);// what about the order here?q.registerStoredProcedureParameter("COUNTRY", String.class, ParameterMode.IN);q.registerStoredProcedureParameter("TOTAL", Integer.class, ParameterMode.OUT);

// setup the parametersq.setParameter("COUNTRY", "Poland");

// execute and retrieve the resultsq.execute();Integer total = (Integer) q.getOutputParameterValue("TOTAL");List<Employee> list = (List<Employee>) q.getResultList();

Page 37: Thinking Beyond ORM in JPA

Copyright © 2014 Oracle and/or its affiliates. All rights reserved. |

Example: Stored ProcedureEntityManager API// create and setup a stored procedure queryq = em.createStoredProcedureQuery("GET_EMPLOYEES", Employee.class);// what if we switch the lines?q.registerStoredProcedureParameter("TOTAL", Integer.class, ParameterMode.OUT);q.registerStoredProcedureParameter("COUNTRY", String.class, ParameterMode.IN);

// setup the parametersq.setParameter("COUNTRY", "Poland");

// execute and retrieve the resultsq.execute();Integer total = (Integer) q.getOutputParameterValue("TOTAL");List<Employee> list = (List<Employee>) q.getResultList();

Page 38: Thinking Beyond ORM in JPA

Copyright © 2014 Oracle and/or its affiliates. All rights reserved. |

Example: Stored ProcedureEntityManager API// create and setup a stored procedure queryq = em.createStoredProcedureQuery("GET_EMPLOYEES", Employee.class);// what about the order here?q.registerStoredProcedureParameter("COUNTRY", String.class, ParameterMode.IN);q.registerStoredProcedureParameter("TOTAL", Integer.class, ParameterMode.OUT);

// setup the parametersq.setParameter("COUNTRY", "Poland");

// execute and retrieve the resultsq.execute();Integer total = (Integer) q.getOutputParameterValue("TOTAL");List<Employee> list = (List<Employee>) q.getResultList();

Page 39: Thinking Beyond ORM in JPA

Copyright © 2014 Oracle and/or its affiliates. All rights reserved. |

Example: Stored ProcedureEntityManager API// create and setup a stored procedure queryq = em.createStoredProcedureQuery("GET_EMPLOYEES", Employee.class);// what about the order of the positional parameters?q.registerStoredProcedureParameter(2, Integer.class, ParameterMode.OUT);q.registerStoredProcedureParameter(1, String.class, ParameterMode.IN);

// setup the parametersq.setParameter("COUNTRY", "Poland");

// execute and retrieve the resultsq.execute();Integer total = (Integer) q.getOutputParameterValue("TOTAL");List<Employee> list = (List<Employee>) q.getResultList();

Page 40: Thinking Beyond ORM in JPA

Copyright © 2014 Oracle and/or its affiliates. All rights reserved. |

Example: Stored ProcedureEntityManager API// create and setup a stored procedure queryq = em.createStoredProcedureQuery("GET_EMPLOYEES", Employee.class);// what about the order of the positional parameters?q.registerStoredProcedureParameter(2, Integer.class, ParameterMode.OUT);q.registerStoredProcedureParameter(1, String.class, ParameterMode.IN);

// setup the parametersq.setParameter("COUNTRY", "Poland");

// execute and retrieve the resultsq.execute();Integer total = (Integer) q.getOutputParameterValue("TOTAL");List<Employee> list = (List<Employee>) q.getResultList();

Page 41: Thinking Beyond ORM in JPA

Copyright © 2014 Oracle and/or its affiliates. All rights reserved. |

Example: Stored ProcedureAnnotation@NamedStoredProcedureQuery { name = "getEmployees", procedureName = "GET_EMPLOYEES", resultClasses = Employee.class, parameters = { @StoredProcedureParameter(name="COUNTRY", mode=ParameterMode.IN, type=String.class), @StoredProcedureParameter(name="TOTAL", mode=ParameterMode.OUT, type=Integer.class) }}@Entitypublic class Employee { // … }

Page 42: Thinking Beyond ORM in JPA

Copyright © 2014 Oracle and/or its affiliates. All rights reserved. |

Example: Stored ProcedureEntityManager API// create and setup a stored procedure queryStoredProcedureQuery q = em.createNamedStoredProcedureQuery("getEmployees");

// setup the parametersq.setParameter("COUNTRY", "Poland");

// first, an implicit call to executeList<Employee> list = (List<Employee>) q.getResultList();

// ...then, we can safely obtain the output value Integer total = (Integer) q.getOutputParameterValue("TOTAL");

Page 43: Thinking Beyond ORM in JPA

Copyright © 2014 Oracle and/or its affiliates. All rights reserved. |

Example: Stored ProcedureEntityManager API// create and setup a stored procedure queryStoredProcedureQuery q = em.createNamedStoredProcedureQuery("getEmployees");

// setup the parametersq.setParameter("COUNTRY", "Poland");

// first, an implicit call to executeList<Employee> list = (List<Employee>) q.getResultList();

// ...then, we can safely obtain the output value Integer total = (Integer) q.getOutputParameterValue("TOTAL");

Page 44: Thinking Beyond ORM in JPA

Copyright © 2014 Oracle and/or its affiliates. All rights reserved. |

Example: Stored ProcedureEntityManager API// create and setup a stored procedure queryStoredProcedureQuery q = em.createNamedStoredProcedureQuery("getEmployees");

// setup the parametersq.setParameter("COUNTRY", "Poland");

// first, an implicit call to executeList<Employee> list = (List<Employee>) q.getResultList();

// ...then, we can safely obtain the output value Integer total = (Integer) q.getOutputParameterValue("TOTAL");

Page 45: Thinking Beyond ORM in JPA

Copyright © 2014 Oracle and/or its affiliates. All rights reserved. |

Example: Stored ProcedureEntityManager API// create and setup a stored procedure queryStoredProcedureQuery q = em.createNamedStoredProcedureQuery("getEmployees");// no calls to registerStoredProcedureParameter// setup the parametersq.setParameter("COUNTRY", "Poland");

// first, an implicit call to executeList<Employee> list = (List<Employee>) q.getResultList();

// ...then, we can safely obtain the output value Integer total = (Integer) q.getOutputParameterValue("TOTAL");

Page 46: Thinking Beyond ORM in JPA

Copyright © 2014 Oracle and/or its affiliates. All rights reserved. |

Example: Stored Procedure-- PostgreSQLCREATE OR REPLACE FUNCTION GET_EMPLOYEES(

IN GIVEN_COUNTRY VARCHAR(255),OUT TOTAL INT) RETURNS REFCURSOR AS

$BODY$DECLARE

EMPS REFCURSOR; BEGIN

OPEN EMPS FOR SELECT * FROM EMPLOYEE WHERE COUNTRY = GIVEN_COUNTRY;

RETURN EMPS;END;$BODY$LANGUAGE plpgsql

Page 47: Thinking Beyond ORM in JPA

Copyright © 2014 Oracle and/or its affiliates. All rights reserved. |

Example: Stored Procedure-- PostgreSQLCREATE OR REPLACE FUNCTION GET_EMPLOYEES(

IN GIVEN_COUNTRY VARCHAR(255),OUT TOTAL INT) RETURNS REFCURSOR AS

$BODY$DECLARE

EMPS REFCURSOR; BEGIN

OPEN EMPS FOR SELECT * FROM EMPLOYEE WHERE COUNTRY = GIVEN_COUNTRY;

RETURN EMPS;END;$BODY$LANGUAGE plpgsql

Page 48: Thinking Beyond ORM in JPA

Copyright © 2014 Oracle and/or its affiliates. All rights reserved. |

Example: Stored ProcedureEntityManager API// create and setup a stored procedure queryStoredProcedureQuery q = em.createStoredProcedureQuery("GET_EMPLOYEES", Employee.class);q.registerStoredProcedureParameter(1, void.class, ParameterMode.REF_CURSOR);q.registerStoredProcedureParameter("COUNTRY", String.class, ParameterMode.IN);

// setup the parametersq.setParameter("COUNTRY", "Poland");

// an implicit call to executeList<Employee> list = (List<Employee>) q.getResultList();

Page 49: Thinking Beyond ORM in JPA

Copyright © 2014 Oracle and/or its affiliates. All rights reserved. |

Example: Stored ProcedureAnnotation@NamedStoredProcedureQuery( name = "getEmployees", procedureName = "GET_EMPLOYEES", resultClasses = Employee.class, parameters = { @StoredProcedureParameter(mode=ParameterMode.REF_CURSOR, type=void.class), @StoredProcedureParameter(name="COUNTRY", mode=ParameterMode.IN, type=String.class) })@Entitypublic class Employee { // … }

Page 50: Thinking Beyond ORM in JPA

Copyright © 2014 Oracle and/or its affiliates. All rights reserved. |

Example: Stored ProcedureEntityManager API// create and setup a stored procedure queryStoredProcedureQuery q = em.createNamedStoredProcedureQuery(”getEmployees”);

// setup the parametersq.setParameter("COUNTRY", "Poland");

// an implicit call to executeList<Employee> list = (List<Employee>) q.getResultList();

Page 51: Thinking Beyond ORM in JPA

Copyright © 2014 Oracle and/or its affiliates. All rights reserved. |

Example: Stored ProcedureAnnotation@NamedStoredProcedureQuery( name = "getEmployees", procedureName = "GET_EMPLOYEES", resultClasses = Employee.class, parameters = { @StoredProcedureParameter(mode=ParameterMode.REF_CURSOR, type=void.class), @StoredProcedureParameter(name="COUNTRY", mode=ParameterMode.IN, type=String.class) })@Entitypublic class Employee { // … }

Page 52: Thinking Beyond ORM in JPA

Copyright © 2014 Oracle and/or its affiliates. All rights reserved. |

Example: Stored ProcedureEntityManager API// create and setup a stored procedure queryStoredProcedureQuery q = em.createNamedStoredProcedureQuery("getEmployees");

// setup the parametersq.setParameter(2, "Poland");

// obtain the resultList<Employee> list = (List<Employee>) q.getResultList();

Page 53: Thinking Beyond ORM in JPA

Copyright © 2014 Oracle and/or its affiliates. All rights reserved. |

Example: Stored ProcedureEntityManager API// create and setup a stored procedure queryStoredProcedureQuery q = em.createNamedStoredProcedureQuery("getEmployees");

// setup the parametersq.setParameter(2, "Poland");

// obtain the resultList<Employee> list = (List<Employee>) q.getResultList();

Page 54: Thinking Beyond ORM in JPA

Copyright © 2014 Oracle and/or its affiliates. All rights reserved. |

Stored Procedures in JPA 2.1Wrap-up• Annotation–@NamedStoredProcedureQuery

• EntityManager API– createStoredProcedureQuery– registerStoredProcedureParameter

• Use cases– Existing database– Abstraction on database level (e.g., for several applications)

• Still differences between databases!–Much smaller though

Page 55: Thinking Beyond ORM in JPA

Copyright © 2014 Oracle and/or its affiliates. All rights reserved. |

Reporting

Page 56: Thinking Beyond ORM in JPA

Copyright © 2014 Oracle and/or its affiliates. All rights reserved. |

Reporting Anti-Patterns• Direct usage of an object-oriented domain model• Too much data loaded• Heavy processing on the Java side

Page 57: Thinking Beyond ORM in JPA

Copyright © 2014 Oracle and/or its affiliates. All rights reserved. |

Reporting Anti-PatternsExample

Page 58: Thinking Beyond ORM in JPA

Copyright © 2014 Oracle and/or its affiliates. All rights reserved. |

Reporting Anti-PatternsEmployee Entity@Entity public class Employee { @Id @GeneratedValue private Long id; private String firstName; private String lastName; private BigDecimal salary; @OneToOne @JoinColumn(name = "address_id") private Address address; @Temporal(TemporalType.DATE) private Date startDate; @Temporal(TemporalType.DATE) private Date endDate; @ManyToOne @JoinColumn(name = "manager_id") private Employee manager; // …}

Page 59: Thinking Beyond ORM in JPA

Copyright © 2014 Oracle and/or its affiliates. All rights reserved. |

Sum of Salaries By CountrySelect All (1)TypedQuery<Employee> query = em.createQuery( "SELECT e FROM Employee e", Employee.class);List<Employee> list = query.getResultList();

// calculate sum of salaries by country// map: country->sumMap<String, BigDecimal> results = new HashMap<>();for (Employee e : list) { String country = e.getAddress().getCountry(); BigDecimal total = results.get(country); if (total == null) total = BigDecimal.ZERO; total = total.add(e.getSalary()); results.put(country, total);}

Page 60: Thinking Beyond ORM in JPA

Copyright © 2014 Oracle and/or its affiliates. All rights reserved. |

Sum of Salaries by CountrySelect Join Fetch (2)TypedQuery<Employee> query = em.createQuery( "SELECT e FROM Employee e JOIN FETCH e.address", Employee.class);List<Employee> list = query.getResultList();

// calculate sum of salaries by country// map: country->sumMap<String, BigDecimal> results = new HashMap<>();for (Employee e : list) { String country = e.getAddress().getCountry(); BigDecimal total = results.get(country); if (total == null) total = BigDecimal.ZERO; total = total.add(e.getSalary()); results.put(country, total);}

Page 61: Thinking Beyond ORM in JPA

Copyright © 2014 Oracle and/or its affiliates. All rights reserved. |

Reporting Anti-PatternsProjection (3)Query query = em.createQuery( "SELECT e.salary, e.address.country FROM Employee e");List<Object[]> list = (List<Object[]>) query.getResultList();

// calculate sum of salaries by country// map: country->sumMap<String, BigDecimal> results = new HashMap<>();for (Object[] e : list) { String country = (String) e[1]; BigDecimal total = results.get(country); if (total == null) total = BigDecimal.ZERO; total = total.add((BigDecimal) e[0]); results.put(country, total);}

Page 62: Thinking Beyond ORM in JPA

Copyright © 2014 Oracle and/or its affiliates. All rights reserved. |

Reporting Anti-PatternsAggregation JPQL (4)Query query = em.createQuery( "SELECT SUM(e.salary), e.address.country FROM Employee e GROUP BY e.address.country");List<Object[]> list = (List<Object[]>) query.getResultList();

// already calculated!

Page 63: Thinking Beyond ORM in JPA

Copyright © 2014 Oracle and/or its affiliates. All rights reserved. |

Reporting Anti-PatternsAggregation SQL (5)Query query = em.createNativeQuery( "SELECT SUM(e.salary), a.country FROM employee e JOIN address a ON e.address_id = a.id GROUP BY a.country");List<Object[]> list = (List<Object[]>) query.getResultList();

// already calculated!

Page 64: Thinking Beyond ORM in JPA

Copyright © 2014 Oracle and/or its affiliates. All rights reserved. |

Comparison 1-5100 000 employees, EclipseLink

MySQL PostgreSQLSelect all (1+N) (1) 25704ms 18120msSelect join fetch (2)Projection (3)Aggregation JPQL (4)Aggregation SQL (5)

Page 65: Thinking Beyond ORM in JPA

Copyright © 2014 Oracle and/or its affiliates. All rights reserved. |

Comparison 1-5100 000 employees, EclipseLink

MySQL PostgreSQLSelect all (1+N) (1) 25704ms 18120msSelect join fetch (2) 6211ms 3954msProjection (3)Aggregation JPQL (4)Aggregation SQL (5)

Page 66: Thinking Beyond ORM in JPA

Copyright © 2014 Oracle and/or its affiliates. All rights reserved. |

Comparison 1-5100 000 employees, EclipseLink

MySQL PostgreSQLSelect all (1+N) (1) 25704ms 18120msSelect join fetch (2) 6211ms 3954msProjection (3) 533ms 569msAggregation JPQL (4)Aggregation SQL (5)

Page 67: Thinking Beyond ORM in JPA

Copyright © 2014 Oracle and/or its affiliates. All rights reserved. |

Comparison 1-5100 000 employees, EclipseLink

MySQL PostgreSQLSelect all (1+N) (1) 25704ms 18120msSelect join fetch (2) 6211ms 3954msProjection (3) 533ms 569msAggregation JPQL (4) 410ms 380msAggregation SQL (5) 380ms 409ms

Page 68: Thinking Beyond ORM in JPA

Copyright © 2014 Oracle and/or its affiliates. All rights reserved. |

MySQL vs. PostgreSQL

68

Select

all (1

+N) (1)

Select

join fetch

(2)

Projection (3

)

Aggrega

tion JPQL (

4)

Aggrega

tion SQL (

5)0

50001000015000200002500030000

25704

6211533 410 380

18120

3954569 380 409 MySQL

PostgreSQL

Page 69: Thinking Beyond ORM in JPA

Copyright © 2014 Oracle and/or its affiliates. All rights reserved. |

ProjectionJPQL -> Value ObjectQuery query = em.createQuery( "SELECT new com.yonita.jpa.vo.EmployeeVO(e.salary, e.address.country) FROM Employee e");

// The list of value objectsList<EmployeeVO> list = (List<EmployeeVO>) query.getResultList();

Page 70: Thinking Beyond ORM in JPA

Copyright © 2014 Oracle and/or its affiliates. All rights reserved. |

ProjectionJPQL -> Value ObjectQuery query = em.createQuery( "SELECT new com.yonita.jpa.CountryStatVO( sum(e.salary), e.address.country) FROM Employee e GROUP BY e.address.country");

// The list of value objectsList<CountryStatVO> list = (List<CountryStatVO>) query.getResultList();

Page 71: Thinking Beyond ORM in JPA

Copyright © 2014 Oracle and/or its affiliates. All rights reserved. |

ProjectionSQL -> Value Object@SqlResultSetMapping( name = "countryStatVO", classes = { @ConstructorResult( targetClass = CountryStatVO.class, columns = { @ColumnResult(name = "ssum", type = BigDecimal.class), @ColumnResult(name = "country", type = String.class) }) } )

Page 72: Thinking Beyond ORM in JPA

Copyright © 2014 Oracle and/or its affiliates. All rights reserved. |

ProjectionSQL -> Value ObjectQuery query = em.createNativeQuery("countryStatVO");

// The list of value objectsList<CountryStatVO> list = (List<CountryStatVO>) query.getResultList();

Page 73: Thinking Beyond ORM in JPA

Copyright © 2014 Oracle and/or its affiliates. All rights reserved. |

Projection Wrap-up• JPA 2.0 – Only JPQL query to directly produce a value object!

• JPA 2.1– JPQL and native queries to directly produce a value object!

• Managed entities– Sync with database– L1/L2 cache

• Use cases for Direct Value Object– Reporting, statistics, history– Read-only data, GUI data

• Performance– No need for managed objects– Rich (or fat) managed objects– Subset of attributes required– Gain speed– Offload an app server

Page 74: Thinking Beyond ORM in JPA

Copyright © 2014 Oracle and/or its affiliates. All rights reserved. |

AggregationWrap-up• JPA 2.0 – Selected aggregation functions: COUNT, SUM, AVG, MIN, MAX

• JPA 2.1– All function as supported by a database– Call any database function with new FUNCTION keyword

• Database-specific aggregate functions– MS SQL: STDEV, STDEVP, VAR, VARP,…– MySQL: BIT_AND, BIT_OR, BIT_XOR,…– Oracle: MEDIAN, PERCENTILE,…– More…

• Use cases– Reporting, statistics– Performance

• Gain speed• Offload an app server to a database!

Page 75: Thinking Beyond ORM in JPA

Copyright © 2014 Oracle and/or its affiliates. All rights reserved. |

Complex Queries

Page 76: Thinking Beyond ORM in JPA

Copyright © 2014 Oracle and/or its affiliates. All rights reserved. |

JPQL vs. SQL• Column/table visibility– JPA 2.0/2.1: Only mapped columns and tables

• Operations on sets– UNION, INTERSECT, EXCEPT– JPA 2.0/2.1: No support

• Nested fetch joins– JPA 2.0: No support– JPA 2.1: entity graphs for different fetching strategies

• ON– JPA 2.0: No support– JPA 2.1: Only on “connected entities”

Page 77: Thinking Beyond ORM in JPA

Copyright © 2014 Oracle and/or its affiliates. All rights reserved. |

JPQL vs. SQL• Database functions– Aggregate functions– Conversion functions– Extraction functions–Manipulation functions– Functions, functions, functions…– JPA 2.0: Selected functions– JPA 2.1: All functions

Page 78: Thinking Beyond ORM in JPA

Copyright © 2014 Oracle and/or its affiliates. All rights reserved. |

Helper Functions JPA 2.1• String functions: – CONCAT, SUBSTRING, TRIM, LOWER, UPPER, LENGTH, LOCATE

• Arithmetic functions: – ABS, SQRT, MOD, SIZE, INDEX

• Date/time functions: – CURRENT_DATE, CURRENT_TIME, CURRENT_TIMESTAMP

• Aggregate functions:– COUNT, SUM, MIN, MAX, AVG

• Invocation of predefined or user-defined functions: – FUNCTION(function_name {, function_args}*)

Page 79: Thinking Beyond ORM in JPA

Copyright © 2014 Oracle and/or its affiliates. All rights reserved. |

Helper Functions JPA 2.1• Invocation of predefined or user-defined functions: – FUNCTION(function_name {, function_args}*)– SELECT c

FROM Customer cWHERE FUNCTION(‘hasGoodCredit’, c.balance, c.creditLimit)

Page 80: Thinking Beyond ORM in JPA

Copyright © 2014 Oracle and/or its affiliates. All rights reserved. |

JPA 2.1

Page 81: Thinking Beyond ORM in JPA

Copyright © 2014 Oracle and/or its affiliates. All rights reserved. |

Wrap-up• JPA 2.1– Stored procedures support– Projections• Direct value object for native queries

– Richer JPQL

Page 82: Thinking Beyond ORM in JPA

Copyright © 2014 Oracle and/or its affiliates. All rights reserved. |

Wrap-up• JPA 2.1– Stored procedures support– Projections• Direct value object for native queries

– Richer JPQL

• Performance

Page 83: Thinking Beyond ORM in JPA

Copyright © 2014 Oracle and/or its affiliates. All rights reserved. |

Wrap-up• JPA 2.1– Stored procedures support– Projections• Direct value object for native queries

– Richer JPQL

• Performance– Don’t load if you don’t need

Page 84: Thinking Beyond ORM in JPA

Copyright © 2014 Oracle and/or its affiliates. All rights reserved. |

Wrap-up• JPA 2.1– Stored procedures support– Projections• Direct value object for native queries

– Richer JPQL

• Performance– Don’t load if you don’t need– Don’t execute many small queries if you can execute one big query

Page 85: Thinking Beyond ORM in JPA

Copyright © 2014 Oracle and/or its affiliates. All rights reserved. |

Wrap-up• JPA 2.1– Stored procedures support– Projections• Direct value object for native queries

– Richer JPQL

• Performance– Don’t load if you don’t need– Don’t execute many small queries if you can execute one big query– Don’t calculate if a database can

Page 86: Thinking Beyond ORM in JPA

Copyright © 2014 Oracle and/or its affiliates. All rights reserved. |

A fool with a tool is still a fool!

Page 87: Thinking Beyond ORM in JPA

Copyright © 2014 Oracle and/or its affiliates. All rights reserved. |

Continuous Learning Paradigm

87

Page 88: Thinking Beyond ORM in JPA

Copyright © 2014 Oracle and/or its affiliates. All rights reserved. |

Q+A

Page 89: Thinking Beyond ORM in JPA

Copyright © 2014 Oracle and/or its affiliates. All rights reserved. |

Keep Learning with Training from Oracle University

89

• Hands-on training delivered in-class or online by tenured instructors around the world

• New subscription-based learning services to give you any-time access to training

• Certification programs to validate your skills

education.oracle.com

Page 90: Thinking Beyond ORM in JPA

Copyright © 2014 Oracle and/or its affiliates. All rights reserved. |

Thank You for Joining Us TodayPlease Move to the Next Session.

90

Page 91: Thinking Beyond ORM in JPA

Copyright © 2014 Oracle and/or its affiliates. All rights reserved. | 91

Page 92: Thinking Beyond ORM in JPA

Copyright © 2014 Oracle and/or its affiliates. All rights reserved. | 92