410013796724260
• Webmoney
R335386147728
Z369087728698
Hibernate в вопросах и ответах
1. Что такое Hibernate Framework?Hibernate — это библиотека с открытым исходным кодом (open source) для Java, предназначенная для решения задач ORM (object-relational mapping, объектно-реляционного отображения). Она представляет собой свободное программное обеспечение, распространяемое на условиях GNU Lesser General Public License. Hibernate Framework имеет легкий в использовании каркас для отображения объектно-ориентированной модели данных в традиционные реляционные базы данных и предоставляет стандартные средства JPA. 2. Преимущества использования Hibernate Framework?Библиотека Hibernate является одним из самых востребованных ORM фреймворков для Java, поскольку :
3. Объекты Hibernate SessionFactory, Session и Transaction
Пример использования объектов SessionFactory, Session, Transaction. 4. Конфигурационный файл HibernateФайл конфигурации hibernate.cfg.xml содержит информацию о базе данных (драйвер, пул подключений, диалект) и параметрах подключения к серверу БД (url, login, password). В качестве параметров подключения можно использовать как JDBC, так и JNDI. В файле конфигурации также определяются дополнительные параметры, которые будут использованы при работе с сервером БД, Так, здесь необходимо определить маппинги сущностей/классов. Чтобы отобразить в консоли SQL-скрипты, генерируемые Hibernate, необходимо в hibernate.cfg.xml определить истиное значение свойства «show_sql». Помните, что это необходимо использовать только на уровне разработки и тестирования. В финальной версии свойство «show_sql» должно быть отключено. Пример файла конфигурации связанных сущностей. 5. Файл mappingФайл отображения (mapping file) используется для связи entity бинов с таблицами базы данных. Содержимое файла имеет формат XML. Файл mapping можно использовать вместо аннотаций JPA. Особенно он становится необходимым при использовании сторонних библиотек.Пример файла отображения. 6. Важные аннотации для отображения в HibernateНаиболее употребительные аннотации Hibernate из пакета javax.persistence представлены в следующей таблице :
Подробнее об аннотациях в сущностных бинах. 7. Отличие методов openSession и getCurrentSessionМетоды openSession и getCurrentSession объекта SessionFactory возвращают сессию Session. Метод getCurrentSession объекта SessionFactory возвращает сессию, связанную с контекстом. Но для того, чтобы метод вернул не NULL, необходимо настроить параметр current_session_context_class в конфигурационном файле hibernate. Поскольку полученный объект Session связан с контекстом hibernate, то отпадает необходимость в его закрытии; он закрывается вместе с закрытием SessionFactory. <property name="hibernate.current_session_context_class"> thread </property> Метод openSession объекта SessionFactory всегда создает новую сессию. В этом случае необходимо обязательно контролировать закрытие объекта сессии по завершению всех операций с базой данных. Для многопоточной среды необходимо создавать новый объект Session для каждого запроса. При загрузке больших объемов данных без удержания большого количества информации в кэше можно использовать метод openStatelessSession(), который возвращает Session без поддержки состояния. Полученный объект не реализует первый уровень кэширования и не взаимодействует со вторым уровнем. Сюда же можно отнести игнорирование коллекций и некоторых обработчиков событий. 8. Отличие методов get и load объекта SessionДля загрузки информации из базы данных в виде набора/коллекции сущностей объект Session имеет несколько методов. Наиболее часто используемые методы get и load. Метод get загружает данные сразу же при вызове, в то время как load использует прокси объект и загружает данные только тогда, когда это требуется на самом деле (при обращении к данным). В этом плане load имеет преимущество в плане ленивой загрузки данных. Метод load вызывает исключение, если данные не найдены. Поэтому load нужно использовать только при уверенности в существовании данных. Если необходимо удостовериться в наличии данных в БД, то нужно использовать метод get. 9. Различные состояния Entity BeanСущность Entity Bean может находиться в одном из трех состояний :
Из состояний transient и detached объект можно перевести в состояние persistent в виде нового объекта после вызова метода merge(). 10. Отличия методов save, saveOrUpdate и persistМетод save используется для сохранения сущности в базе данных. Этот метод возвращает сгенерированный идентификатор. Возникаемые проблемы с использованием save связаны с тем, что метод может быть вызван без транзакции. А следовательно если имеется отображение нескольких связанных объектов, то только первичный объект будет сохранен, т.е. можно получить несогласованные данные. Метод hibernate persist аналогичен save, но выполняется с транзакцией. Метод persist не возвращает сгенерированный идентификатор сразу. Метод saveOrUpdate используется для вставки или обновления сущности. Если объект уже присутствуют в базе данных, то будет выполнен запрос обновления. Метод saveOrUpdate можно применять без транзакции, но это может привести к аналогичным проблемам, как и в случае с методом save. 11. Использование метода сессии mergeМетод Hibernate merge объекта сессии может быть использован для обновления существующих значений. Необходимо помнить, что данный метод создает и возвращает копию из переданного объекта сущности. Возвращаемый объект является частью контекста персистентности с отслеживанием любых изменений, а переданный объект не отслеживается. 12. Отсутствие в Entity Bean конструктора без параметровHibernate использует рефлексию для создания экземпляров Entity бинов при вызове методов get или load. Для этого используется метод Class.newInstance, который требует наличия конструктора без параметров. Поэтому, в случае его отсутствия, будет вызвано исключение HibernateException. 13. Entity Bean не должна быть finalHibernate использует прокси классы для ленивой (lazy) загрузки данных (т.е. не сразу, а по необходимости). Это достигается с помощью расширения Entity Bean. Отсюда следует, что если бы он был final, то это было бы невозможно. Ленивая загрузка данных во многих случаях повышает производительность, а следовательно важна и от нее не следует отказываться. 14. Сортировка данных в HibernateПри использовании алгоритмов сортировки из Collection API используется сортированный список (sorted list). Для маленьких коллекций это не приводит к излишнему расходу ресурсов. Однако на больших коллекциях это может привести к потере производительности и ошибкам OutOfMemory. Entity Bean'ы для работы с сортированными коллекциями должны реализовывать интерфейс Comparable/Comparator. При использовании фреймворка Hibernate для загрузки данных можно применить Collection API и команду order by для получения сортированного списка (ordered list). Ordered list является лучшим способом получения sorted list, т.к. используется сортировка на уровне базы данных, работающая быстрее и не приводящая к утечке памяти. Пример запроса к БД для получения ordered list : List<Employee> list = session.createCriteria(Employee.class) .addOrder(Order.desc("id")).list(); Hibernate использует следующие типы коллекций : Bag, Set, List, Array, Map. 15. Использование Query Cache в HibernateHibernate реализует область кэша для запросов ResultSet, который тесно взаимодействует с кэшем второго уровня Hibernate. Для подключения этой дополнительной функции необходимо определить истинное значение свойства hibernate.cache.use_query_cache в файле конфигурации hibernate.cfg.xml и в коде при обращении к БД использовать метод setCacheable(true). Кэшированные запросы полезны только при их частом исполнении с повторяющимися параметрами. Определение свойства в файле конфигурации Hibernate : <property name="hibernate.cache.use_query_cache"> true </property> Формирование запроса с использованием метода setCacheable (true) : Query query = session.createQuery("from Employee"); query.setCacheable(true); query.setCacheRegion("ALL_EMP"); 16. Язык запросов HQLHibernate включает мощный язык запросов HQL (Hibernate Query Language), который очень похож на родной SQL. В сравнении с SQL, HQL полностью объектно-ориентирован и использует понятия наследования, полиформизма и связывания. HQL использует имя класса взамен имени таблицы, а также имя свойства вместо имени колонки. Пример HQL : Query query = session.createQuery("from ContactEntity where firstName = :paramName"); query.setParameter("paramName", "Nick"); List list = query.list(); 17. Нативный SQL-запрос в HibernateДля выполнения нативного запроса необходимо использовать SQLQuery, который может выполнять чистый SQL-запрос. Но необходимо учитывать, что в этом случае можно потерять все преимущества HQL (ассоциации, кэширование). Пример нативного SQL-запроса : String sql ; Query query; sql = "select id, name, salary from employees"; query = session.createSQLQuery(sql).addEntity(Employee.class); List<Employee> list = query.list(); for (Iterator<Employee> it = users.iterator(); it.hasNext();) { Employee employee = (Employee) it.next(); System.out.println(employee.toString()); } Обратите внимание, что при формировании Query был добавлен класс Employee.class, в результате чего метод list() объекта Query вернул коллекцию сотрудников List<Employee>. В следующем коде при формировании Query нет привязки к конкретному классу. В результате метод list() возвращает коллекцию объектов List<Object[]>. query = session.createSQLQuery(sql); List<Object[]> rows = query.list(); for(Object[] row : rows) { Employee emp = new Employee(); emp.setId (Long.parseLong (row[0].toString())); emp.setName (row[1].toString()); emp.setSalary (Double.parseDouble(row[2].toString())); System.out.println(emp); } 18. Преимущества поддержки нативного SQL-запросаИспользование нативного SQL может быть необходимо при выполнении некоторых запросов к базам данных, которые могут не поддерживаться в Hibernate. Т.е. включение в запросы специфичных для БД «фишек». 19. Именованный запрос, Named SQL QueryHibernate поддерживает использование именованных запросов, которые можно определить в одном месте и использовать в любом месте в коде. Именованные запросы поддерживают как HQL, так и Native SQL. Для создания Named SQL Query можно использовать JPA аннотации @NamedQuery, @NamedNativeQuery или конфигурационный файл отображения (mapping files). Пример описания и использования Named SQL Query. // Определение Named SQL Query @NamedQuery( name = "getContacts", query = "select ce from ContactEntity ce where ce.id >=:id" ) // Сущность @Entity @Table(name="contact", schema = "", catalog = "javastudy") public class ContactEntity { } . . . // использование Named SQL Query Query query = session.getNamedQuery("getContacts") .setString("id", "10"); 20. Преимущества именованных запросов Named SQL QueryNamed Query имеют глобальный характер, т.е. заданные в одном месте, доступны в любом месте кода. Синтаксис Named Query проверяется при создании SessionFactory, что позволяет заметить ошибку на раннем этапе, а не при запущенном приложении и выполнении запроса. Одним из основных недостатков именованного запроса является то, что его сложнее отлаживать. Сложности могут быть связаны с поиском места определения запроса. Поэтому не разбрасывайтесь описанием запросов в различных участках. Можно все связанные с сущностью запросы описать непосредственно в классе, используя аннотацию @NamedQueries, как это показано в следующем коде : @Entity @Table(name="student") @NamedQueries({ @NamedQuery(name="selectStudents", query="select st from Student st"), @NamedQuery(name="updateStudentRecord", query="update Student st set st.sname =: name where st.id =:id") }) public class Student { . . . } 21. Использование org.hibernate.CriteriaHibernate Criteria API представляет альтернативный подход HQL и позволяет выполнять запросы в БД без написания SQL кода. Для создания экземпляров Criteria используется класс Session. Пример Criteria с необязательным обрамлением в транзакцию : session.beginTransaction(); List<User> users users = session.createCriteria(User.class) .setMaxResults(10).list(); session.getTransaction().commit(); Приведенный выше запрос вернет первые 10 записей из таблицы сущности User. Метод setMaxResults представляет собой аналог команды LIMIT в SQL-запросе. Чтобы прочитать определенное количество записей с с определенной позиции (LIMIT 2, 15) необходимо дополнительно использовать метод setFirstResult : List<User> users users = session.createCriteria(User.class) .setFirstResult(2) .setMaxResults(15).list(); Подробнее о org.hibernate.Criteria можно прочитать здесь. 22. Hibernate proxy и ленивая загрузка (lazy load)Hibernate может использовать прокси для поддержки отложенной загрузки. При соответствующем атрибут fetch аннотации связи (fetch определяет стратегию загрузки дочерних объектов) из базы данных не загружаются связанные объекты. При первом обращении к дочернему объекту с помощью метода get, если связанная сущность отсутствует в кэше сессии, то прокси код перейдет к базе данных для загрузки связанной сущности. Для этого используется javassist, чтобы эффективно и динамически создавать реализации подклассов Entity Bean объектов. Подробнее об атрибуте загрузки связанных объектов fetch. 23. Каскадные связиПри наличии зависимостей (связей) между сущностями необходимо определить влияние различных операций одной сущности на связанные. Это можно реализовать с помощью аннотации каскадных связей @Cascade. Пример использования @Cascade : import org.hibernate.annotations.Cascade; @Entity @Table(name = "EMPLOYEE") public class Employee { @OneToOne (mappedBy="employee") @Cascade (value=org.hibernate.annotations.CascadeType.ALL) private Address address; } Помните, что имеются некоторые различия между enum CascadeType в Hibernate и в JPA. Поэтому обращайте внимание на импортируемый пакет при использовании аннотации и константы типа. Наиболее часто используемые CascadeType перечисления описаны ниже :
24. Управление транзакциямиHibernate не допускает большинство операций без использования транзакций. Для начала транзакции необходимо выполнить метод beginTransaction объекта сессии Session, возвращающий ссылку, которую можно использовать для подтверждения или отката транзакции. Любое вызываемое в Hibernate исключение автоматически вызывает rollback. Использование JNDI DataSource в HibernateПри использовании Hibernate в WEB-приложении и определении соответствующих настроек в контейнере сервлетов, касающихся подключения Datasource, можно использовать JNDI. Для этого необходимо в файле конфигурации hibernate.cfg.xml определить свойство hibernate.connection.datasource : <property name="hibernate.connection.datasource"> java:comp/env/jdbc/MyLocalDB </property> |