Аннотации

Аннотации были введены в Java 5 и для них сразу нашлось куча применений. Ведь аннотация позволяет вам получить дополнительную информацию о любом объекте языка — классе, методе, поле. Конечно же сам создатель языка не мог пройти мимо и очень быстро был опубликован JPA — Java Persistance API (Java API для хранения). И он содержал много удобных и полезных аннотаций, которые взяли на вооружение многие популярные пакеты.
Не думаю, что нам потребуется для знакомства с аннтоациями описывать весь язык Java — думаю более важно, чтобы вы ухватили суть. Аннотация (и ее параметры) может быть прочитана в момент исполнения. Следовательно необходимая информация может быть записана прямо в файле.

Некоторую информацию по аннотациям вы можете найти в моей статье Что нового в Java SE 5.0

Само собой Hibernate тоже не остался в стороне. Теперь разработчик не должен создавать дополнительные XML-файлы — всю необходимую информацию он может описать прямо в файле с Entity. Что несомненно гораздо удобнее. Вы очень быстро привыкните — я привык к этому за 2-3 дня. Теперь описание в XML мне кажется просто кощунством :).

Зайдите на страницу Hibernate. Слева будет в меню, в котором мы выбираем пункт Download. В списке реализаций выбираем «Hibernate Annotations». В загруженном архиве будет список библиотек и документация, которую обязательно надо будет читать и пробовать использовать. Для текущего проекта нам понадобятся следующие библиотеки:
antlr-2.7.6.jar
commons-collections-3.1.jar
commons-logging.jar
dom4j-1.6.1.jar
ejb3-persistence.jar
hibernate-annotations.jar
hibernate-commons-annotations.jar
hibernate3.jar
javaee.jar
javassist-3.4.GA.jar
jta-1.1.jar
log4j-1.2.15.jar
mysqlJDBC-3.1.13.jar
slf4j-api-1.5.3.jar
slf4j-log4j12-1.5.3.jar

Изменения коснутся файлов с описаниями Entity — Profession, Subject, Applicant, ApplicantResult. Несколько изменится файлHibernateUtil.java. И наконец придется внести изменения в файл hibernate.cfg.xml. Это будет теперь единственный XML-файл в нашем проекте (до некоторого момента).

hibernateUtil.java

Как видите здесь очень мало изменений. Мы просто изменили конфигуратор — теперь наш конфигуратор умеет работать с аннотациями.

Думаю, что здесь комменарии вряд ли потребуются — у нас произошла замена класса Configuration на AnnotaionConfiguration. В общем это все.

Теперь посмотрим файл hibernate.cfg.xml

Здесь мы видим небольшое изменение в форме записи зарегистрированных Entity — теперь мы пишем не XML-файлы, а сами классы.

И наконец начинается самое важное и интересное — мы посмотрим, как делать аннотации в классах. Для начала рассмотрим файл Applicant.java

Давайте рассмотрим все аннотации, которые встретились нам в данном файле. Надеюсь, вы знаете, что аннотации начинаются с симовола @.
Для начала рассмотрим аннотации для класса целиком.

  • @Entity — говорит о том, что данный класс представляет собой сущность, которую надо сохранять в базе данных
  • @Table — показывает, какая таблица используется для хранения

Теперь пройдем по всему списку полей и посмотрим их назначение. Сначала мы рассмотрим аннотации для первичного ключа — applicantId

  • @Id — говорит о том, что данное поле является идентификатором
  • @GeneratedValue — аннотация дает указание, что данная величина будет генериться, причем указаниеstrategy=GenerationType.IDENTITY говорит о том, что значение будет создано с помощью базы данных — точнее значение столбца, который связан с полем будет генерится с помощью базы данных.
  • @Column — достаточно очевидная аннотация для указания имени столбца, с которым связано поле класса.

Посмотрим на аннотации для поля profession

  • @ManyToOne — аннотация указывает, что поле указывает на другой класс, который связан с текущим классом связью многие-к-одному. Здесь также указывается правило каскада cascade= {CascadeType.REFRESH} — в упрощенном виде оно гласит «что сделали с тобой, то сделай и со связью». В нашем случае единственная операция, которая будет передаваться на класс Profession — это перечитывание. Все остальные операции не будут распространяться на связанный класс. Запись fetch=FetchType.LAZY указывает, что загрузка данного поля будет только в случае обращения к данному полю. Пока программа этого не делает, поле будет пустым.
  • @JoinColumn — данная анотация по сути похожа на @Column. Разве что она указывает, что колонка к тому же является связующей

Ну и наконец поле applicantResultList

  • @OneToMany — такая запись говорит о том, что поле служить для связи один-ко-многим (потому и список). Единственный параметр, который мы еще не рассмотрели — mappedBy=»applicant». Он указывает имя поля в классе ApplicantResult, которое будет указывать на «родителя» — на класс Applicant

 

Теперь можно посмотреть на реализацию класса ApplicantResult

Думаю, что здесь вы не встретите того, что мы не рассматривали ранее для класса Applicant. Осталось совсем немного — рассмотреть два классаProfession и Subject.

Начнем с класса Subject

Здесь мы видим еще один вариант записи связи — много-ко-многим. Посмотрим на параметры:

  • @ManyToMany — эта аннотация говорит о том, что поле будет использовано для связи много-ко-многим.
  • @JoinTable — указывает имя таблицы, которая используется для организации связи много-ко-многим. Параметр joinColumns указывает название столбца, которые явялется ссылкой на текущий класс, т.е. на Subject (точнее ссылкой на таблицу SUBJECT). ПараметрinverseJoinColumns указывает на колонку, в которй находится ссылка на класс с другой стороны отношения — в данном случае этоProfession. Думаю, что при внимательном рассмотрении вы поймете, что и как

Ну а теперь мы можем посмотреть файл Profession.java

 

Здесь тоже приводится вариант отношения много-ко-многим. Предлагаю вам разобрать его самостоятельно.

Само собой мы не рассмотрели еще очень большое количество аннотаций, которые предлагает JPA и сам Hibernate — они заслуживают вашего внимания. Но подробное рассмотрение всех аннотаций не входит в планы автора. Напоследок я приведу код файлов, которые мы не меняли -StudentDAO.java и Main.java

StudentDAO.java

Main.java

Как видите, теперь вам не надо создавать кучу XML-файлов. Кроме того, вы сразу можете видеть, какое поле с каким столбцом в какой таблице связано, что очень упрощает разработку. Вот в принципе и все, что я хотел рассказать об аннотациях Hibernate.

Что дальше ?

Конечно же мы рассмотрели очень немного из того, что предоставляет программисту Hibernate. Далее мы не будем рассматривать какие-либо аспекты этого пакета, хотя нам могут встречаться более сложные примеры или просто другие примеры использования данного пакета. Прежде чем закончить обозрение, я бы хотел перечислить те области, которые есть смысл проработать самим по документации

  1. Постраничное получение данных. Основная идея в том, чтобы получать не полный список всех записей, а только ограниченное количество. Это крайне удобно при больших обхемах данных. Нередко пользователи вводят очень неудачный критерий поиска и размер данных становится просто огромный. При страничной организации вы отдаете только ограниченный набор данных и в качестве удобства общее количество. Если задать количество записей на странице, то путем несложных вычислений можно будет получить общее количество страниц и начальный номер записи для каждой страницы. Посмотрите внимательно на интерфейс org.hibernate.Query. У него есть методы setFirstResult иsetMaxResults. Они и определяют то, что надо. Обратите внимание, что каждый SQL сервер имеет свои способы получения ограниченного количества записей. Так что оригинальный запрос SQL будет отличаться для ORACLE и для MySQL.
  2. HQL — Hibernate Query Language. Это язык, напоминающий обычный SQL, но для работы с объектами Hibernate. Язык достаточно мощный и вы не пожалеете время, которое потратили на его хорошее изучение. HQL предоставляет достаточно большое количетсво интересных и полезных функций, так что изучайте.
  3. Именованые запросы — NamedQuery. Когда вы создаете HQL запрос (а даже обычный запрос вроде FROM Subject уже является HQL-запросом), то Hibernate предпринимает некоторые действия для перевода HQL в SQL. Для запросов, которые можно заранее создать, удобно использовать NamedQuery. Такие запросы заранее «компилируются» в SQL и затраты времени сокращаются. Обратите внимание, что такие запросы могут использовать параметры. Т.е. запрос может быть «наполовину статическим»
  4. Наследование. Как я уже упоминал, Hibernate позволяет создавать иерархию классов, которая будет отображаться на одну или несколько таблиц. Для более подробного ознакомления обратитесь к документации. Интересным могут оказаться аннотации javax.persistence.Basic иjavax.persistence.AttributeOverride. Это стандартные J2EE аннотации, которые позволяют определять разные названия столбцов в таблице для разных классов
  5. Аннотации. И еще раз об аннотациях — смотрите их список и изучайте. Они действительно достойны этого. Например Formula — позволяет для поля задать SQL-выражение, которое будет вычисляться. Или Filter, которая позволяет включать фильтр для отсечения неугодных записей. Подобное делает и Where. В общем читайте и старайтесь использовать их в своих проектах.
  6. Native SQL. Учтите, что Hibernate полностью заменить SQL не может. Он все-таки объектно ориентирован. Нередко встречаются задачи (особенно при создании крупных и сложных финансовых отчетов), которые требуют именно SQL. Hibernate позволяет вам использовать обычный SQL в этом случае. Это конечно сложнее, но если такая возможность есть — надо о ней знать

Собственно это все, о чем бы я хотел упомянуть в заключительной части по Hibernate. Теперь самое время приступить к изучению пакета, который помогает организовать бизнес-уровень. Встречайте — Часть 19 — Spring. Бизнес-уровень в действии.

 

Архив с исходными кодами: Исходный код

6 comments to Hibernate. Аннотации вместо XML

  • Марко  says:

    Здравствуйте, Антон, столкнулся со странной проблемой:
    при прямом запросе к базе данных (через Netbeans) получаю нормальный результат, запрос следующий: «select * from student where last_name like ‘П%'», где П — русская буква(база данных тоже заполнена русскими именами, сharset ‘utf8’) — то есть всё нормально. Но когда z использую Hibernate — нет: создаю всё необходимое cfg, reveng, util, entity, выполняю из cfg.xml «Run HQL query»: обычный запрос вроде «from Student» или «from Student where course = 3» работает нормально, но если пытаюсь использовать русскую букву вроде «from Student where lastName like ‘П%'» — ничего не находит. Подскажите, пожалуйста, в чём может быть проблема. Заранее спасибо

    • admin  says:

      Я бы обратил внимание на два момента:
      1. В какой кодировке создана база данных и в какой кодировке работает сам SQL
      2. В соединении с MySQL хорошо бы указывать кодировку явно — jdbc:mysql://localhost:3306/st_student?characterEncoding=UTF-8

  • Стас  says:

    Добрый день, а вот если сущность SPECIALITY_SUBJECT (связь profession и subject) содержала бы поля — дата начала связи и дата окончания связи, тогда имеет смысл создать отдельный класс @Entity для данной сущности или есть какое-то другое решение?

    • admin  says:

      В принципе существует фильтрация (@Filtering) на основе аннотаций, правда я пробовал ее только для OneToMany. Будет ли такая штука работать для ManyToMany — надо пробовать. Если не получится, то наверно придется делать сущность и накладывать на нее ограничения.

  • Владимир  says:

    Добрый день, Антон! Вопрос: подскажите можно ли сделать метод в котором с помощью HQL отфильтровать всех Applicant по объекту Proffession? Именно по объекту, а не по по вторичному ключу id_profession?
    Т.е. могли бы Вы подсказать код метода вида dao.getListApplicant(Profession profession)?
    Заранее спасибо!

    • admin  says:

      Можно. Вы же можете сделать свой собственный запрос на HQL — вот и придумайте.

Leave a reply

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code class="" title="" data-url=""> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong> <pre class="" title="" data-url=""> <span class="" title="" data-url="">

Лимит времени истёк. Пожалуйста, перезагрузите CAPTCHA.