Hibernate для чайников. Часть 1.
Для начала о себе я не являюсь дипломированным или сертифицированным специалистом по java и hibernate, поэтому все что будем мною изложено в данной статье было подчеркнуто из документации и личного опыта.
Начинаем. Для чего все это нужно. Hibernate - это механизм отображения в реляционной базе данных объектов java. Используемые для работы библиотеки можно загрузить с сайта http://hibernate.org. Нам понадобятся Hibernate Core непосредственно сама библиотека, и Hibernate Annotations для поддержки описаний объектов (можно обходиться и без нее но тогда нужно использовать другие методы для инициализации отображаемых объектов). Прямых ссылок на загрузку я не даю потому как проект постоянно развивается и ссылки могут устареть, думаю с загрузкой с сайта проблем возникнуть не должно. Также нужен запущенный SQL сервер (какой вам больше нравится), и ясно дело jdbc драйвера на него.
Не мастер я объяснять поэтому сразу к примерам на них все и поймете. Допустим вы хотите написать небольшое приложение для хранения каталога фильмов в базе данных. Для в Hibernate это будет выглядеть следующим образом. Создадим пару классов для работы с данными:
// Video.java
package org.media;
...
public class Video {
private Long id;
private String description;
public void setId(Long id){this.id = id;}
public Long getId(){return id;}
....
}
// Actor.java
package org.media;
...
public class Actor {
private Long id;
private String name;
private Date birthday;
public void setId(Long id){this.id = id;}
public Long getId(){return id;}
....
}
//Cast.java
package org.media;
...
public class Cast {
private Long id;
private Video video;
private Actor actor;
public void setId(Long id){this.id = id;}
public Long getId(){return id;}
....
}
Структура вроде понятна фильмы, актеры и связка актеры которые снимались в фильме. Оговорюсь сразу что тип реквизита должен быть обязательно объект, а не базовые типы как int, long, boolean, вместо них следует использовать Integer, Long, Boolean. Два слова для тех кто собирается хранить данные с фиксированной дробной частью (ака денежные единицы) используете для этих целей BigDecimal. Начнем издеваться над этими тремя объектами для начала оговорюсь что я буду использовать аннотации поэтому вам понадобиться jdk 1.5 и дополнительный пакет hibernate-annotations. Начнем для начала нам нужно определить что эти обекты будут храниться (отображаться) в базе данных это достигается добавлением в код следующего
// Video.java
package org.media;
...
@Entity
@Table(name= «video»)
public class Video {
@Entity говорит о том что этот объект будет обрабатываться hibernate, @Table(name= «video») , что он будет храниться в таблице video.
Особенностью работы hibernate является то что каждый хранимый объект должен иметь уникальный ключ (идентификатор), в нашем случае этим ключем является реквизит private Long id, чтобы правильно определиться для hibernate этот реквизит добавляем следующее :
....
public class Video {
@Id
@Column(name= «id»)
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String description;
что мы при это получаем, @Id говорит о том что следующий реквизит является ключем для текущего объекта, @Column(name= «id») - необязательная запись определяет имя колонки для хранения ключа, и @GeneratedValue(strategy = GenerationType.AUTO) используется в том случае если вы хотите чтобы hibernate при создании новых объектов сам заполнял значение ключа (подробнее читать в документации), т.е. если вы не против устанавливать значение id вручную данное поле можно опустить. движемся дальше к простым полям с данными
....
private Long id;
@Column(name= «description», length=64)
private String description;
Ну здесь и так все понятно текущий реквизит будет храниться в нашей таблице в колонке с именим description и длинна этого поля будет составлять 64 символа.
В итоге получаем следующее :
// Video.java
package org.media;
...
@Entity
@Table(name= «video»)
public class Video {
@Id
@Column(name= «id»)
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@Column(name= «description», length=64)
private String description;
public void setId(Long id){this.id = id;}
public Long getId(){return id;}
....
}
Опуская импорт и реализацию гетеров и сетеров, мы имеем класс готовый для отображения в hibernate, т.е. нам потребовалось пара описаний для самого класса, отдельно описание для реквизита ключа, и описание для стандартных реквизитов. Движемся дальше. в ряде случаев, например для реквизитов типа Data, Hibernate требует указание дополнительных аннотаций:
// Actor.java
package org.media;
...
private String name;
@Column(name= «birthday»)
@Temporal(value=TemporalType.DATE)
private Date birthday;
Добавившеяся новая аннотация @Temporal(value=TemporalType.DATE) говорит о том, что реквизит будет использоваться для хранения даты, также есть варианты хранения времени и даты и времени. Обращаю внимание что Hibernate не выполняет приведение типа дата автоматически, т.е. в нашем случае при birthday=new Date(); birthday хранит и дату и время, и только после сохранения и повторной загрузки время будет усечено.
Теперь непосредственно осталось самое вкусное - хранение ссылок на пользовательские классы. Эта операция не требует ничего сверхестественного, только для пользовательских классов используются специфические аннотации и именно связи между объектами, всего их три ManyToOne, ManyToMany, OneToOne. Последние две рассматривать не будем если кому интересно все есть в документации. Приступим к нашему примеру.
//Cast.java
...
public class Cast {
//Все как и раньше
....
private Long id;
@ManyToOne
@JoinColumn(name= «video»)
private Video video;
@ManyToOne
@JoinColumn(name= «actor»)
private Actor actor;
....
}
Собственно и все при помощи @ManyToOne мы выполняем привязку объектов друг к другу, @JoinColumn(name= «actor») определяет имя поля в таблице (если не указывать имя полю будет присвоено автоматически, потом в таблица сложно будет разобраться поэтому я предпочитаю указывать все явно).
Ну что можно сказать наши объекты готовы дело за малым начать их использование.
Для работы с Hibernate мы должны выполнить несколько шагов по инициализации.
- Инициализировать базу данных для работы
- Определить объекты которые будут отображаться в базе данных
- Непосредственно начать работу с данными
Начнем с начала, Hibernate для своей работы требует специальный файл конфигурации, к слову вместо аннотаций принято использовать конфигурацию классов в этом файле или других внешних, которые все равно импортируются в нем. Имя этого файла hibernate.cfg.xml, располагаться он должен в самом корне дерева классов. Он представляет из себя правильных xml документ следующего вида
<!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="connection.driver_class">org.postgresql.Driver;</property>
<property; name="connection.url">jdbc;:postgresql://127.0.0.1/media</property>
<property; name="connection.username">media;</property>
<property; name="connection.password">123456;</property>
<property; name="connection.pool_size">1;</property>
<property; name= "cache.provider_class">
org.hibernate.cache.NoCacheProvider
</property>
<property; name="dialect">org.hibernate.dialect.PostgreSQLDialect;</property>
<property; name="show_sql">true;</property>
<property; name="hbm2ddl.auto">update;</property>
<property; name="current_session_context_class">thread;</property>
</session-factory>
</hibernate-configuration>
Как видите большинство свойств перекликаются с подобными в JDBC. Коснемся только важных для нас свойств connection.driver_class – драйвер для подключения к БД, connection.url – адрес для подключения, connection.username – имя пользователя имеющего право доступа к БД, connection.password – ну куда уж без него. Все покончили с файлом конфигурации, начинаем его использование, т.е. на данном этапе становиться ясно что доступ к БД определяется этим файлом.
Теперь непосредственно к реализации. Создаем служебный класс например HibernateUtil и добавляем в него следующие строки:
static{
try{
AnnotationConfiguration aconf = new AnnotationConfiguration()
.addAnnotatedClass(Video.class)
.addAnnotatedClass(Actor.class)
.addAnnotatedClass(Cast.class);
Configuration conf = aconf.configure();
На данном этапе мы загрузили данные из файла конфигурации
Configuration conf=aconf.configure();
и навязали на его голову работу с нашими классами посредством .addAnnotatedClass(...)
Практически все. Hibernate для работы реализует механизм фактори (не знаю как перевести), через него мы и будем работать с нашими данными и именно создавать Сессии подключения для доступа к данным.
Вот наша фактори, ее можно инициализировать в статическом блоке. На данном шаге в базе данных будут созданы необходимые для работы таблицы и т.п., но есть одно «но» ,база данных должна уже быть создана до настоящего шага.
Ну теперь понеслась, сохранение данных программы
Video video = new Video();
video.setId();
video.setDescription(«Калигула»);
я подразумеваю что сеттер вы сами написали
Actor actor – new Actor();
actor.setId(new Long(1));
Представим что я не указывал для актеров @GeneratedValue(strategy = GenerationType.AUTO)
actor.setName(«Телка из массовки звать Маня»);
Cast cast = new Cast();
cast.setVideo(video);
cast.setActor(actor);
Session session = factory.openSession();
session.beginTransaction();
session.saveOrUpdate(video);
session.saveOrUpdate(actor);
session.saveOrUpdate(cast);
session.getTransaction().commit();
session.close();
После выполнения commit() данные из наших java классов благополучно перекочевали в таблицы SQL сервера. Кому интересно можно сразу посмотреть в вашу БД и полюбоваться наличием заданных данных в ваших таблицах.
Ну, а теперь пару примеров о получении данных из БД. Почему пару, наверное потому что хочу подробнее расписать это все в следующих статьях.
Session session = factory.openSession();
Actor actor = (Actor)session.get(Actor.class,new Long(1));
session.close();
System.out.println(actor.getName());
либо так:
Session session = factory.openSession();
List
В первом случае получаем актера с id равным 1, во втором список из названий фильмов.
Собственно для первой статьи наверное хватит.