Translate

четвер, 1 листопада 2012 р.

EclipseLink ORM Persistence Framework


Для більшості java рограмістів сьогодні Hibernate == ORM. проте є ряд інших, не менш цікавих ORM, які можуть виявитися куди більш підходящим для вашого проекту, ніж улюблений Хібернейт.
Хочу звернути вашу увагу на EclipseLink, який пішов від ораклівського TopLink і сьогодні являє більш ніж підтримку персістенсу через JPA, але також JAXB, JCA та SDO (простими словами - можна працювати з XML, веб-сервісами чи но-скл базами). Але я сфокусуюся саме на ORM стороні цього рішення, і без дискутування чому ORM це погано і треба обережно совати його до свого проекту:)
Пропоную розглянути, як EclipseLink може допомогти, якщо на проекті Оракл СКБД



 Отже, більшість знайомі з Хібернейтом, або з JPA in general. Хочу поділитися своїм досвідом використання EclipseLink, після інтенсивної роботи з Hibernate.
Перший плюс EclipseLink - це етелонна реалізація JPA (хоча це привносить і свої мінуси). Другий, і найбільш вагомий плюс - велика кількість Оракл-орієнтед плюшек, про які піде нижче - отже, якщо на вашому проекті Оракл і ви не плануєте підтримути якісь інші СКБД, то вам прямий шлях до використання EclipseLink, а не Хібернейт. І по-третє, статус з багами в кожному з проектів (as for July 26, 2011):
 Name            - Number of bugs    -   Number of blockers   -  The oldest blocker 
 Hibernate      -          156               -              49                    -     29/Sep/2006 
 EclipseLink  -           15                 -              3                     -     04/Jun/2010 

(!) Перед використанням слід обов"язково ознайомитися з інструкцією по використання, бо на вас чекатимуть різноманітні підводні камені. Один з найбільш підступних - це кеш другого рівня, який по замовчуваню увімкнений (це WeakHashMap)

Ну а тепер про обіцяні плюшки для Ораклу:
1) EclipseLink вміє вписувати хінти до кверів,
коли під"єднаний до Оракла, а також має АПІ який дозволяє вам самостійно додавати хінти: наприклад, з банально
Query query = em.createQuery("SELECT e FROM Employee e ORDER BY e.lastName ASC, e.firstName ASC");
query.setFirstResult(5);
query.setMaxResults(5);
List<Employee> emps = query.getResultList();
Ви отримаєте ось такий SQL запит (і одразу біндінг, без додаткових налаштувань логування як у хібернейту)
SELECT * FROM (SELECT /*+ FIRST_ROWS */ a.*, ROWNUM rnum  FROM (
 SELECT  t0.EMP_ID AS EMP_ID1, t1.EMP_ID AS EMP_ID2, t0.F_NAME AS F_NAME3, t0.L_NAME AS L_NAME4, t0.START_TIME AS START_TIME5, 
  t0.END_TIME AS END_TIME6, t0.GENDER AS GENDER7, t1.SALARY AS SALARY8, t0.VERSION AS VERSION9, t0.START_DATE AS START_DATE10, 
  t0.END_DATE AS END_DATE11, t0.MANAGER_ID AS MANAGER_ID12, t0.ADDR_ID AS ADDR_ID13 
    FROM EMPLOYEE t0, SALARY t1 
    WHERE (t1.EMP_ID = t0.EMP_ID) ORDER BY t0.L_NAME ASC, t0.F_NAME ASC) a WHERE ROWNUM <= ?) WHERE rnum > ?
 
bind => [10, 5]
Як бачите, підказка оптимізатору самостійно з"явилася в запиті

 2) Підтримка ієрархічних запитів оракла
 Не певен щодо перекладу, мова йде про Hierarchical Queries http://docs.oracle.com/cd/B19306_01/server.102/b14200/queries003.htm
ReadAllQuery raq = new ReadAllQuery(Employee.class);
// Specifies a START WITH expression
Expression startExpr = expressionBuilder.get("id").equal(new Integer(1));
// Specifies a CONNECT BY expression
Expression connectBy = expressionBuilder.get("managedEmployees");
// Specifies an ORDER SIBLINGS BY vector
Vector order = new Vector();
order.addElement(expressionBuilder.get("lastName"));
order.addElement(expressionBuilder.get("firstName"));
raq.setHierarchicalQueryClause(startExpr, connectBy, order);
Vector employees = uow.executeQuery(raq);
Буде перетворено на щось типу
SELECT * FROM EMPLOYEE START WITH ID=1 CONNECT BY PRIOR ID=MANAGER_ID ORDER SIBLINGS BY LAST_NAME, FIRST_NAME
Безціна функціональність, якщо доводеться багато оперувати з ієрархічними структурами

 3) Підтримка Oracle Flashback Transaction Query 
Ніколи не використовував цей функціонал, і чесно кажу навіть не уявляю, кому він може стати в нагоді (хто знає - поділіться досвідом)

 4) Альтернативний спосіб викликати stored procedures, відміний від Хібернейтівського
 Тобто, в хібернейті сторед процедуру можна описати, наприклад в hbm.xml чи jpa @NamedStoredProcedureQuery тоді як на додачу до JPA-way, EclipseLink підтримує ще й StoredFunctionCall клас для динамічного формування виклику до деякої сторед процедури, а-ля:
StoredFunctionCall functionCall = new StoredFunctionCall();
functionCall.setProcedureName("CHECK_VALID_EMPLOYEE");
functionCall.addNamedArgument("EMP_ID");
functionCall.setResult("FUNCTION_RESULT", String.class);
ValueReadQuery query = new ValueReadQuery();
query.setCall(functionCall);
query.addArgument("EMP_ID");
List args = new ArrayList();
args.addElement(new Integer(44));
String valid = (String) session.executeQuery(query, args);

Ще одна корисна штукенція, наче підтримується для всіх СКБД, це АПІ для "репортинг запитів". Тобто, якщо вам треба заюзати в коді AVG, SUM і тд, то не треба писати SQL (чи інші його варіації) - можно просто використати ReportQuery, який дозволяє побудувати таку кверю через маніпулювання методами
ReportQuery query = new ReportQuery(Employee.class, emp);
query.addMaximum("max-salary", emp.get("salary"));
query.addAverage("average-salary", emp.get("salary"));
query.addAttribute("city", emp.get("address").get("city"));
на цьому огляд важливих фіч EclipseLink можна завершити

Роблячи вибір, слід пам"ятатти що Хібернейт має власні специфічні плюшки, і слід зважити який функціонал вам буде більш потрібний