Любое корпоративное приложение имеет в своем составе уровень хранения (Persistence layer). Java Persistence API (JPA) предоставляет разработчикам набор инструментов, позволяющих решать задачи по работе с хранимыми данными и ORM. В данной статье я хочу показать как начать использовать JPA 2.0.
Прежде всего разберемся с терминологией. Мы разрабатываем некоторое приложение на объектно-ориентированном языке (Java) и хотим сохранить результаты его работы в реляционной базе данных. В связи с этим возникает задача преобразовать объекты (с которыми мы работаем в приложении) в форму, в которой они могут быть сохранены в базе данных и легко (а главное без потерь) извлечены в последующем. В этом нам поможет ORM – object-relational mapping – объектно-реляционное отображение – преобразование данных из объектной формы в реляционную и наоборот.
Перед нами стоит задача отобразить модель, представленную на рисунке ниже:

У нас есть схема, состоящая из одной сущности: Customer. Предположим, что это часть предметной области некоторого электронного магазина, описывающая покупателя, имеющего аттрибуты: имя, фамилия, номер кредитной карты.
Давайте создадим приложение, которое реализует данную схему в объектном виде, отображает её в реляционную базу данных, а также позволяет осуществлять взаимодействие приложения с БД.
При разработке я использовал Netbeans 6.9.1 (в максимальной комплектации).
Начнем с создания и конфигурирования приложения, использующего JPA в Netbeans. Первым делом создадим базу данных, с которой будет работать наше приложение. Для простоты будем использовать Derby DB. Во вкладке Services выберите Databases. В появившемся списке щелкните правой кнопкой мыши по Java DB, в меню выберите Create Database...

В диалоговом окне необходимо ввести название новой БД, имя пользователя и пароль:

Нажимаем OK. Мы создали базу данных online_shop, которую будем использовать для нашего проекта. Также автоматически было создано Database Connection, которое потребуется нам в дальнейшем.
Теперь перейдем к созданию проекта.
Для этого нажмите File → New Project... → Java → Java Application → Next >
В появившемя окне введите в качестве названия OnlineShop, нажмите Finish. Теперь проект успешно создан.
Настала пора реализовать сущность Customer. Так как мы хотим, чтобы в дальнейшем объекты данного класса могли быть сохранены в базе данных (для этого мы и используем JPA), вместо создания обычного класса Customer необходимо создать так называемый класс-сущность (Entity). По сути, Entity – обычный Java-класс, который должен удовлетворять нескольким требованиям. Создадим наш первый Entity. Кликните на созданном проекте правой кнопкой мыши → New → Entity Class... В появившемся диалоговом окне укажите название класса-сущности и пакет, где он будет располагаться:

Нажмите Next.
Для Netbeans создание Entity является сигналом о том, что необходимо использовать ORM-фреймворк. Здесь я хочу отметить одну важную вещь: Java Persistence API сама по себе не является ORM-реализацией. JPA предоставляет единый, стандартизированный интерфейс для работы с ORM-фреймворками. Получается мы работаем со следующей связкой: JPA + Persistence Provider (понятия ORM-реализацией, ORM-фреймворк, Persistence Provider являются синонимами). В качестве Persistence Provider мы можем использовать любой фреймворк, реализующий JPA 2.0, например, EclipseLink, Hibernate, OpenJPA.
В появившемся окне нам предлагают настроить ORM-реализацию:

Особо обратим внимание на следующие установки:
В качестве Persistence Library мы выбрали EclipseLink с указанием, что будем использовать ее вместе с JPA 2.0;
В поле Database Connection мы указали название соединения к созданной нами на первом этапе базе;
Нажимаем на Finish, и наш первый класс-сущность готов! Обратите внимание, что кроме создания нового класса, в проект была добавлена библиотека EclipseLink, а также создана директория META-INF с файлом persistence.xml. Помимо всего прочего данный файл содержит информацию об используемом с JPA ORM-фреймворке, а также настройки соединения с базой данных:
<persistence-unit name="OnlineShopPU" transaction-type="RESOURCE_LOCAL">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<class>com.onlineshop.mapping.Customer</class>
<properties>
<property name="javax.persistence.jdbc.url" value="jdbc:derby://localhost:1527/online_shop"/>
<property name="javax.persistence.jdbc.password" value="12345"/>
<property name="javax.persistence.jdbc.driver" value="org.apache.derby.jdbc.ClientDriver"/>
<property name="javax.persistence.jdbc.user" value="user"/>
<property name="eclipselink.ddl-generation" value="drop-and-create-tables"/>
</properties>
</persistence-unit>
Прежде чем приступить к редактированию созданных классов, необходимо добавить в проект библиотеки для работы с DerbyDB. Их расположение можно узнать, кликнув по пункту Properties в контекстном меню Java DB:

Библиотеки расположены в папке lib каталога, указанного в Java DB Installation (то есть в моем случае /usr/lib/jvm/java-6-sun/db/lib):

Ваш путь, скорее всего, будет отличаться от представленного. Далее щелкните правой кнопкой мыши по приложению, в меню выберите Properties, в открывшемся окне перейдите на вкладку Libraries, нажмите Add Library..., нажмите Create, в качестве названия введите Derby и добавьте jar файлы, расположенные в папке lib каталога, где у вас находится Java DB (определение этого пути описано выше). Затем добавьте Derby к остальным библиотекам пректа.
Теперь немного модифицируем класс Customer, чтобы он соответствовал требуемой в модели сущности Customer. Добавим необходимые поля и конструкторы (часть автосгенерированного кода опущена):
package com.onlineshop.mapping;
import java.io.Serializable;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
@Entity
public class Customer implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String name;
private String surname;
private Long cardNumber;
public Customer() {
}
public Customer(String name, String surname, Long cardNumber) {
this.name = name;
this.surname = surname;
this.cardNumber = cardNumber;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
…
}
Давайте посмотрим, чем сущность Customer отличается от обычного класса.
Перед объявлением класса стоит аннотация @Entity. Она говорит о том, что данный класс должен быть отображен в базу данных. Сущесвуют некоторые требования, которым должен удовлетворять класс-сущность, вот некоторые из них: он не должен быть final, не должен иметь отображаемых аттрибутов с модификатором final, должен содержать конструктор без аргументов (определенный пользователем или по умолчанию), а доступ извне к полям объекта должен осуществляться через соответствующие get и set методы. В нашем примере видно, что класс содержит два конструктора, один из которых без аргументов, а для каждого поля есть свои get и set методы.
Перед объявлением поля id стоят аннотации @Id и @GeneratedValue. Аннотация @Id говорит о том, что аттрибут, перед которым она установлена (в нашем случае id) должен уникально определять экземпляр данного класса. С помощью @GeneratedValue мы указываем стратегию генерации идентификатора (в нашем случае AUTO – решение за нас принимает Persistence Provider).
Во всем остальном Customer – обычный Java-класс.
На рисунке ниже показано, как данный класс будет представлен в базе данных:

При объектно-реляционном отображении созданный нами класс Customer отображается на таблицу CUSTOMER, аттрибуты класса проецируются на столбцы таблицы: аттрибуту id соответствует столбец ID, аттрибуту name соответствует столбец Name, аттрибуту surname – столбец SURNAME, аттрибуту cardNumber – столбец CardNumber. При сохранении некоторого объекта Customer он будет представлен в таблице CUSTOMER одной записью.
Теперь для того, чтобы осуществить отображение, осталось модернизировать класс Main. Добавим в Main следующие импорты и поля, а также переопределим метод main (класс Main должен быть сгенерирован Netbeans'ом при создании проекта):
package onlineshop;
import com.onlineshop.mapping.Customer;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
public class Main {
public static final EntityManagerFactory emf = Persistence.createEntityManagerFactory("OnlineShopPU");
public static EntityManager em = emf.createEntityManager();
public static void main(String[] args) {
Customer cust1 = new Customer("Ivan", "Ivanov", 12345L);
em.getTransaction().begin();
em.persist(cust1);
em.getTransaction().commit();
}
}
Чтобы отобразить объект в базу данных, необходимо некоторым образом “сообщить” ORM-фреймворку о нашем желании. В Java Persistence API для этого существует специальный интерфейс – EntityManager, в котором определены все действия, которые мы можем совершить над объектом (объявлены методы для работы с хранимыми данными). ORM-фреймворк реализует этот интерфейс.
В нашем примере мы получаем EntityManager через класс Persistence и объект EntityManagerFactory:
public static final EntityManagerFactory emf = Persistence.createEntityManagerFactory("OnlineShopPU");
public static EntityManager em = emf.createEntityManager();
Рассмотрим изменения в методе main:
Сначала мы создаем экземпляр сущности Customer
Customer cust1 = new Customer("Ivan", "Ivanov", 12345L);
В main через EntityManager мы получаем транзакцию:
em.getTransaction().begin();
Потом сохраняем сущность в базе:
em.persist(cust1);
При успешном выполнении метода присходит commit транзакции:
em.getTransaction().commit();
Теперь можно запустить проект. В результате работы наша объектная модель отображена в реляционную схему, а также в созданную таблицу Customer была занесена запись пользователя Ivan Ivanov (Services → Databases → подключаемся к нашей БД → смотрим таблицу).
Подробнее о настройках сущностей, работе с EntityManager и транзакциями, а также о создании связей будет рассказано в следующих статьях данного цикла. Если у вас остались вопросы, или вы хотите больше узнать об ORM и возможностях JPA 2.0, приходите к нам на мастер-классы.