Использование Hibernate Java Persistence
Содержание
1. Основные технологии хранения данных в java2. Пример реализации Hibernate JPA
2.1. Файл настроек pom.xml проекта для Maven’а
2.2. Настройка параметров подключения к базе данных
2.3. Бизнес - модель данных
2.4. Бизнес - логика
3. Рекомендуемые ресурсы
1. Основные технологии хранения данных в java
Не секрет, что данные являются основой практически для любого проекта. На основе требований к программной системе строится модель данных. В дальнейшем именно с данной моделью работает программа, вводится некоторая информация, производятся вычисления, формируются отчеты и т. д. В процессе развития программных систем проектировались и используются различные системы управления базами данных (СУБД), иерархические, реляционные, объектные и др.
На практике наибольшую популярность получили именно реляционные модели баз данных, хотя в современных методологиях программирования пользуется популярностью объектно-ориентированное программирование. Для стыковки данных технологий разработано множество технологий, спецификаций и фреймворков для маппинга объектов на таблицы реляционных баз данных. Java разработчикам доступно множество технологий для работы с данными это может быть просто сереализация объектов, JDBC, JDO и множество других. Но каждая из них имеет ряд достоинств и недостатков.
Таблица 1. Основные технологии хранения данных в java
| Поддержка | Сериализация | JDBC | ORM | ODB | EJB2 | JDO | JPA |
|---|---|---|---|---|---|---|---|
| Java Объекты | Есть | Нет | Есть | Есть | Есть | Есть | Есть |
| Объектно ориентированный подход | Есть | Нет | Есть | Есть | Нет | Есть | Есть |
| Танзакционность | Нет | Есть | Есть | Есть | Есть | Есть | Есть |
| Параллелизм | Нет | Есть | Есть | Есть | Есть | Есть | Есть |
| Работа с наборами данных | Нет | Есть | Есть | Есть | Есть | Есть | Есть |
| Схема данных | Нет | Есть | Есть | Нет | Есть | Есть | Есть |
| Хранение данных в реляционном и нереляционном форматах | Нет | Нет | Нет | Нет | Есть | Есть | Нет |
| Поддержка запросов к данным | Нет | Есть | Есть | Есть | Есть | Есть | Есть |
| Переносимость и жесткие стандарты | Есть | Нет | Нет | Нет | Есть | Есть | Есть |
| Простота | Есть | Есть | Есть | Есть | Нет | Есть | Есть |
-
Сериализация (Serialization) является встроенным механизмом хранения и передачи объектов в Java. Но для практической работы с данными данный подход мало пригоден, так как требуется извлекать и хранить весь граф объектов, что затрудняет работу с большими объемами данных.
-
Java Database Connectivity (JDBC) Application programming interface (API) разрабатывался для работы с реляционными базами данных. Минусом данной технологии является отсутствие механизмов проекции реляционных данных на объекты, что существенно увеличивает объем кода для данного преобразования.
-
Object-relational mapping (ORM) представляет собой попытки различных поставщиков маппинга объектов на реляционные данные. Отсутствие стандартов привело к созданию множества реализаций данного подхода несовместимых друг с другом. Как результат код становится непереносимым и жестко завязаннм на конкретного поставщика.
-
Object databases (ODB) представляют собой объектные реализации баз данных. Как и в случае с ORM здесь множество реализаций, несмотря на попытки Object Database Management Group (ODMG) создать и стандартизировать API для доступа к объектным базам данных.
-
Enterprise Java Beans (EJB) введены в Enterprise Edition платформе Java уровня предприятия. Сущности EJB 2 представляют собой компоненты для хранения в хранилищах данных. Данная технология позволяет работать с данными на уровне объектов. Варианты физического хранения данных не лимитированы только реляционными базами данных. К сожалению, в стандарте EJB 2.x лимитирован объектно-ориентированный подход. Это выражается в отсутствии или сложности реализации таких важных функций как наследование, полиморфизм и внешние связи объектов. Дополнительные проблемы возникают из-за необходимости применения дорогих и “тяжеловесных” серверов.
-
Спецификация JDO на текущий момент является одной из самых прогрессивных и позволяет использовать не только реляционные, но и объектные хранилища данных.
-
Java Persistence API (JPA) сочетает в себе простоту сериализации объектов с возможностью работы с данными на уровне объектно-ориентированной модели. При этом остается возможность комбинирования доступа к данным как в JDBC на уровне реляционных данных, что позволяет порой достичь большей производительности и гибкости по сравнению с JDO.
На текущий момент существует множество реализаций спецификации JPA, как коммерческих, так и свободных с открытым исходным кодом(open source).
2. Пример реализации Hibernate JPA
Рассмотрим пример использования реализации Hibernate JPA для простых Java Standart Edition (SE) приложений. Идея данного проекта в создании максимально упрощенной архитектуры приложения, т.е. сведению к минимуму количества всевозможных настроек и фокусировании только на поставленной задаче. Java разработчики которые ранее имели дело с Hibernate смогут оценить всю мощь нововведений. Применение аннотаций для внедрения в код служебной информации позволяет освободиться от десятков служебных XML файлов с описанием маппинга java бинов на таблицы баз данных.
Задача: Требуется создать методы для доступа и манипулирования информацией о клиентах.
При помощи утилиты сборки проектов Maven 2 создадим базовую структуру проекта.
Замечание
Применение Maven позволяет абстрагироваться от применяемой разработчиком интегрированной среды разработки. Достаточно вызвать задачу по созданию проекта, например mvn eclipse:eclipse для Eclipse IDE, mvn jdev:jdev для Oracle java Developer или mvn idea:idea для Idea. Вторая особенно ценная функция Maven заключается в создании локального репозитория требуемых java библиотек и автоматического разрешения зависимостей. Это позволяет быстро обновлять библиотеки и устранить дублирование таковых от проекта к проекту. На сайте проекта Maven есть простое руководство, на основе которого можно получить общее представление о приемах работы с данным продуктом. За 10-15 минут можно научиться создавать новые проекты, собирать билды и т.д.
2.1. Файл настроек pom.xml проекта для Maven’а
Файл настроек pom.xml проекта для Maven’а содержит наименование проекта и перечень зависимостей на требуемые библиотеки.
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.berdaflex</groupId>
<artifactId>com.berdaflex.jpa_simple_test</artifactId>
<packaging>jar</packaging>
<version>1.0</version>
<name>Maven Quick Start Archetype</name>
<url>http://maven.apache.org</url>
<dependencies>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate</artifactId>
<version>3.2.1.ga</version>
<type>jar</type>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-annotations</artifactId>
<version>3.2.1.ga</version>
<type>jar</type>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>3.2.1.ga</version>
<type>jar</type>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>javax.persistence</groupId>
<artifactId>persistence-api</artifactId>
<version>1.0</version>
</dependency>
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.3</version>
<type>jar</type>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging-api</artifactId>
<version>1.0.4</version>
<type>jar</type>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.14</version>
<type>jar</type>
<scope>compile</scope>
</dependency>
<!-- JDBC Drivers -->
<dependency>
<groupId>postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>8.2-504.jdbc3</version>
<type>jar</type>
<scope>runtime</scope>
</dependency>
<!-- Test -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
</dependency>
</dependencies>
</project>
Утилита Maven создает проект с разделением программного кода на основной код проекта (src/main/java) и код для тестов (src/test/java), что позволяет легко отделить тесты и не включать их в пакет при конечной сборке проекта. На рисунке 1 показана структура созданного java проекта для Eclipse IDE.
Рисунок 1. Структура java проекта com.berdaflex.jpa_simple_test

2.2. Настройка параметров подключения к базе данных
Проект Hibernate позволяет работать с большим разнообразием популярных СУБД. Постоянно ведется тестирование для следующих баз данных:
-
Oracle 8i, 9i, 10g
-
DB2 7.1, 7.2, 8.1
-
Microsoft SQL Server 2000
-
Sybase 12.5 (JConnect 5.5)
-
MySQL 3.23, 4.0, 4.1, 5.0
-
PostgreSQL 7.1.2, 7.2, 7.3, 7.4, 8.0, 8.1
-
TimesTen 5.1, 6.0
-
HypersonicSQL 1.61, 1.7.0, 1.7.2, 1.7.3, 1.8
-
SAP DB 7.3
-
InterSystems Cache' 2007.1
Так же поддерживается еще много других СУБД (при необходимости можно легко расширить базовый список и добавить свою реализацию требуемого диалекта).
Для тестов выберем популярную Open Source базу данных PostgreSql. Для подключения к базе данных создадим конфигурационный файл hibernate.cfg.xml следующего содержания:
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<property name="hibernate.connection.driver_class">
org.postgresql.Driver
</property>
<property name="hibernate.connection.password">
manager
</property>
<property name="hibernate.connection.url">
jdbc:postgresql://localhost:5432/jpa_test
</property>
<property name="hibernate.connection.username">
postgres
</property>
<property name="hibernate.dialect">
org.hibernate.dialect.PostgreSQLDialect
</property>
<property name="current_session_context_class">thread</property>
<property name="hibernate.hbm2ddl.auto">update</property>
<mapping class="com.berdaflex.contacts.model.Contact" />
</session-factory>
</hibernate-configuration>
Параметр " hibernate.hbm2ddl.auto " устанавливаем в значение “true” для того, чтобы объекты базы данных создавались автоматически на основе маппинга в java-hibernate проекте. Для работы с Hibernate и создания конфигурационных файлов удобно использовать подключаемый модуль Hibernate Tools для Eclipse.
2.3. Бизнес - модель данных
Создадим простой POJO (Plain Old Java Object) объект для хранения данных о контактах. Это типовой JavaBean с доступом к приватным полям через get и set методы. Аннотации можно “привязывать” либо к приватным молям, либо к get методам.
/*******************************************************************************
* Copyright (c) 2005, 2006 Berdaflex Software Systems and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*******************************************************************************/
package com.berdaflex.contacts.model;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;
import org.apache.commons.lang.builder.ToStringBuilder;
/**
* Contact bean.
*
* @author Siarhei Berdachuk
*/
@Entity
@Table(name = "CONTACT")
public class Contact {
private Long contactId;
private String firstName;
private String lastName;
@Id
@GeneratedValue
@Column(name = "CONTACT_ID")
public Long getContactId() {
return contactId;
}
public void setContactId(Long contactId) {
this.contactId = contactId;
}
@Column(name = "FIRST_NAME")
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
@Column(name = "LAST_NAME")
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
@Override
public String toString() {
return new ToStringBuilder(this)//
.append("contactId", getContactId())//
.append("firstName", getFirstName())//
.append("lastName", getLastName())//
.toString();
}
}
Использование javax.persistence аннотаций, позволяет встроить маппинг сущностей используемой системы хранения (в данном случае hibernate) непосредственно в программый код. Это снижает вероятность появления ошибок и теперь не требуется создавать десятки XML файлов маппинга объектов.
Использование стандартизированного API позволяет сменить при необходимости библиотеку реализации Persistence API, например с Hibernate на Oracle Toplink. Аннотация @Entity указывает, что данный класс является сущностью бизнес модели. Аннотация @Table(name = "CONTACT") указывает на имя таблицы в базе данных. Если имя таблицы совпадает с именем класса, то его можно опустить.
Для идентификации конкретной записи в базе данных требуется ключевое поле (аннотация @Id). Чаще всего для этого используется суррогатный ключ. В данном случае для автоматической генерации ключа указываем аннотацию @GeneratedValue. Маппинг атрибутов java бина на колонки таблиц задается при помощи аннотации @Column в дополнительных параметрах которой можно указать наименование колонки таблицы. Если наименование колонок совпадает с именем атрибута, то его можно опустить.
Классы хранимых (persistence) бинов должны быть перечислены в файле конфигурации (строка <mapping class="com.berdaflex.contacts.model.Contact" />).
2.4. Бизнес - логика
Основным интерфейсом для работы с хранимыми объектами является javax.persistence.EntityManager. Некая единица работы с объектами (unit of work) непосредственно осуществляется в типовой связке:
//Получаем конкретный экземпляр реализации интерфейса EntityManager EntityManager em = getEntityManager(); //Начинаем тразакцию em.getTransaction().begin(); //выполняем некоторую обработку бизнес объектов em.persist(объект); . . . //завершаем транзакцию em.getTransaction().commit(); em.close();
Для того чтобы упростить задачу получения конкретного экземпляра реализации интерфейса EntityManager создадим класс помощник (helper) HibernateUtil, который будет автоматически инициализировать конфигурацию Ejb3Configuration на основе созданного нами ранее файла конфигурации Hibernate.
/*******************************************************************************
* Copyright (c) 2005, 2006 Berdaflex Software Systems and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*******************************************************************************/
package com.berdaflex.db.utils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.AnnotationConfiguration;
import org.hibernate.ejb.Ejb3Configuration;
public class HibernateUtil {
public static final Log logger = LogFactory.getLog(HibernateUtil.class
.getName());
private static final SessionFactory sessionFactory;
private static final Ejb3Configuration ejb3Configuration;
static {
try {
// Create the SessionFactory from hibernate.cfg.xml
sessionFactory = new AnnotationConfiguration().configure()
.buildSessionFactory();
ejb3Configuration = new Ejb3Configuration()
.configure("/hibernate.cfg.xml");
} catch (Throwable ex) {
logger.error("Initial SessionFactory creation failed." + ex);
throw new ExceptionInInitializerError(ex);
}
}
public static SessionFactory getSessionFactory() {
return sessionFactory;
}
public static Ejb3Configuration getEjb3Configuration() {
return ejb3Configuration;
}
}
Для получения экземпляра EntityManager теперь можно будет использовать следующую конструкцию:
EntityManager em = HibernateUtil.getEjb3Configuration()
.buildEntityManagerFactory().createEntityManager();
Пример тестов, код которого можно использовать в создаваемых приложениях.
/*******************************************************************************
* Copyright (c) 2005, 2006 Berdaflex Software Systems and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*******************************************************************************/
package com.berdaflex.db;
import javax.persistence.EntityManager;
import javax.persistence.EntityTransaction;
import javax.persistence.Query;
import junit.framework.TestCase;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import com.berdaflex.contacts.model.Contact;
import com.berdaflex.db.utils.HibernateUtil;
/**
* Simple JPA tests.
*
* @author Siarhei Berdachuk
*/
public class HibernateUtilsTest extends TestCase {
public static final Log logger = LogFactory.getLog(HibernateUtilsTest.class
.getName());
@Override
protected void setUp() throws Exception {
super.setUp();
}
@Override
protected void tearDown() throws Exception {
super.tearDown();
}
private void clearData() {
logger.debug("clear test database");
EntityManager em = HibernateUtil.getEjb3Configuration()
.buildEntityManagerFactory().createEntityManager();
EntityTransaction tx = em.getTransaction();
tx.begin();
Query query = em.createQuery(new StringBuilder("delete from ").append(
Contact.class.getName()).toString());
query.executeUpdate();
tx.commit();
em.close();
}
public void testInsertData() {
clearData();
EntityManager em = HibernateUtil.getEjb3Configuration()
.buildEntityManagerFactory().createEntityManager();
em.getTransaction().begin();
Long id_500 = null;
for (int i = 0; i < 1000; i++) {
Contact newContact = new Contact();
newContact.setFirstName(new StringBuilder("FName_").append(i)
.toString());
newContact.setLastName(new StringBuilder("LName_").append(i)
.toString());
em.persist(newContact);
if (i == 500) {
id_500 = newContact.getContactId();
}
}
em.getTransaction().commit();
em.getTransaction().begin();
Contact testContact = em.find(Contact.class, id_500);
assertEquals("FName_500", testContact.getFirstName());
assertEquals("LName_500", testContact.getLastName());
em.getTransaction().commit();
em.close();
}
}



Узнай о чем ты на самом деле сейчас думаешь

