Java Persistency API (JPA) 2.0 также известная как JSR-317 зарелизилась совсем недавно (10 декабря 2009) и до прошлой недели единственным ORM, который полностью реализовывал эту спецификацию, был EclipseLink. Это отличный фреймворк, который, судя по отзывам в сети, работает быстрее чем Hibernate. Однако, на прошлой неделе появился Hibernate 3.5, полностью реализующий спецификацию JPA 2.0. В этой статье я кратко расскажу о новых возможностях JPA 2.0 и Hibernate 3.5.
Вот несколько основных нововведений:
- опция orphanRemoval;
- аннотация ElementCollection;
- аннотация CollectionTable.
Подключение Hibernate 3.5 к проекту
Подключать Hibernate к проекту мы будем как всегда, с помощью Maven 2. Чтобы все заработало, нам понадобится подключить репозиторий JBoss:
<repository> <id>JBoss-Maven-Repository</id> <name>JBoss Maven Repository</name> <url>http://repository.jboss.org/maven2</url> </repository>
Теперь нужно подключить все необходимые зависимости:
<properties> <hibernate-core-version>3.5.0-Final</hibernate-core-version> </properties> ... <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-core</artifactId> <version>${hibernate-core-version}</version> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-annotations</artifactId> <version>${hibernate-core-version}</version> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-entitymanager</artifactId> <version>${hibernate-core-version}</version> </dependency> <dependency> <groupId>javassist</groupId> <artifactId>javassist</artifactId> <version>3.9.0.GA</version> </dependency> <dependency> <groupId>org.apache.derby</groupId> <artifactId>derbyclient</artifactId> <version>10.5.3.0_1</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-jdk14</artifactId> <version>1.5.8</version> </dependency>
Здесь я подключил еще JDBC-драйвер Apache Derby, так как использую его для тестов.
В результате должно получиться такое дерево зависимостей:
Я использую Hibernate 3.5 в JSF-проекте, поэтому на картинке вы видите еще и зависимости JSF. Можете просто не обращать на них внимание.
В документации к Hibernate 3.5 говорится что ядро Hibernate поставляется с Hibernate annotations и Entity Manager’ом, однако, после скачивания зависимостей Maven’ом я заметил, что классы, отвечающие за работу аннотаций и Entity Manager в Core отсутствуют. После недолгих плясок с бубном, выяснилось, что при вытягивании зависимостей из JBoss Maven репозитория, эти пакеты действительно отсутствуют в ядре, а вот если скачать zip-архив hibernate-distribution-3.5.0-Final-dist.zip с сайта JBoss (точнее, с SourceForge), то пакеты annotations и ejb действительно присутствуют в Core. Именно поэтому я добавил в POM зависимости Hibernate Annotations и Hibernate Entity Manager.
Как выяснилось, объясняется это тем, что теперь эти проекты живут в одном SVN-проекте и имеют одинаковый цикл выпуска, а значит и версия у всех этих библиотек одинаковая. Поэтому, я вынес версию библиотек Hibernate в pom.xml в properties.
Стандартные свойства
В более ранних спецификациях JPA (до 2.0) не было определено ни каких стандартных имен для свойств в persistence.xml, поэтому каждый поставщик реализации JPA, должен был сам определить имена свойств. В JPA 2.0 определен небольшой набор стандартных свойств. Сейчас, при настройке persistence.xml можно использовать как имена свойств поставщика реализации (в нашем случае Hibernate), так и стандартизированные имена.
Выглядят они так:
- javax.persistence.jdbc.driver (В Hibernate: hibernate.connection.driver_class)
- javax.persistence.jdbc.user (В Hibernate: hibernate.connection.username)
- javax.persistence.jdbc.password (В Hibernate: hibernate.connection.password)
- javax.persistence.jdbc.url (В Hibernate: hibernate.connection.url)
Думаю, объяснять тут ничего не нужно, т.к. имена свойств говорят сами за себя.
Вот как выглядит мой persistence.xml
<?xml version="1.0" encoding="UTF-8"?> <persistence xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd" version="2.0"> <persistence-unit name="topcodeCorePersistenceUnit" transaction-type="RESOURCE_LOCAL"> <class>ru.topcode.entity.User</class> <exclude-unlisted-classes>true</exclude-unlisted-classes> <properties> <property name="javax.persistence.jdbc.driver" value="org.apache.derby.jdbc.ClientDriver"/> <property name="javax.persistence.jdbc.url" value="jdbc:derby://localhost:1527/topcode_db"/> <property name="hibernate.dialect" value="org.hibernate.dialect.DerbyDialect"/> <property name="javax.persistence.jdbc.user" value="root"/> <property name="javax.persistence.jdbc.password" value="root"/> <property name="hibernate.archive.autodetection" value="class"/> <property name="hibernate.show_sql" value="true"/> <property name="hibernate.format_sql" value="true"/> <property name="hibernate.hbm2ddl.auto" value="create-drop"/> </properties> </persistence-unit> </persistence>
Новые функции маппинга и аннотации
В JPA 2.0 есть ряд новых аннотаций.
Удаление сирот с помощью атрибута orphanRemoval
Сирота – это объект, родительский объект которого был удален. В предыдущей версии JPA не было ни какого эквивалента хибернейтовского DELETE_ORPHAN в cascade type. В JPA 2.0 такое поведение (удаление сирот) можно определить с помощью атрибута orphanRemoval аннотаций ManyToOne и OneToMany. Спецификация определяет два различных сценария поведения orphanRemoval:
- Если целевая сущность была оторвана от сущности-владельца коллекции (один-ко-многим) или ссылке присвоен null, то она (целевая сущность) будет удалена из базы во время выполнения flush.
- Если родительская сущность была удалена, то целевая сущность тоже будет удалена . Другими словами, если orphanRemoval = true, то устанавливать cascade = REMOVE не имеет смысла, т.к. каскадное удаление произойдет в результате применения правила orphanRemoval = true.
Вот пример аннотирования:
@OneToMany(mappedBy="customer",cascade=CascadeType.PERSIST, fetch=FetchType.LAZY, orphanRemoval=true) @BatchSize(size=100) private Set<Order> orders = new HashSet<Order>();
Маппинг коллекции элементов с помощью аннотации ElementCollection
Еще одно нововведение в JPA 2.0 – это эквивалент аннотации CollectionOfElements в Hibernate: аннотация @ElementCollection. С помощью этой аннотации можно замапить коллекцию простых типов или встраиваемых (embeddable) объектов. Вот пример простого маппинга:
public class Customer { .... @ElementCollection private Collection<String> hobbies = new HashSet<String>();
Здесь коллекция строк мапится как атрибут hobbies сущности Customer. Т.к. мы не указали ни каких параметров маппинга, произойдет следующее:
- Имя таблицы будет “customer_hobbies”
- Таблица будет состоять из двух столбцов: “customer_id” – идентификатор клиента, имеющего хобби и “hobbies” – значение хобби. Для каждого элемента в коллекции будет создаваться строка в таблице.
По умолчанию, имя колонки для embedded-данных генерится из имен атрибутов embedded-класса или из имени коллекции (в нашем случае hobbies) для простых типов. Это можно изменить, проаннотировав свойство с типом встроенного класса аннотацией @AttributeOverride или @Column для простых типов:
public class Customer { .... @ElementCollection @Column(name="HOBBY_DATA") private Collection<String> hobbies = new HashSet<String>();
Настроить имя таблицы можно с помощью новой аннотации @CollectionTable:
public class Customer { .... @ElementCollection @Column(name="HOBBY_NAME") @CollectionTable(name="HOBBIES", joinColumns=@JoinColumn(name="CUSTID")) private Collection<String> hobbies = new HashSet<String>();
А так для встраиваемых типов:
@ElementCollection @CollectionTable(name="CUST_ADDITIONAL_ADDRS")private List<Address> additionalAddresses = new ArrayList<Address>();
На сегодня все.



#1 by Васильевич on 6 Май 2010 - 15:04
Quote
Не забываем ставить ссылки на оригинал статьи и упоминать, что это перевод:
http://www.jroller.com/eyallupu/entry/hibernate_3_5_jpa_2
#2 by Cyril Karpenko on 20 Май 2010 - 16:08
Quote
Не написали только об одной из самых важный фич в релизе JPA – поддержке объектного стиля (критериев) при запросе данных.
#3 by Semyon Goryachkin on 24 Май 2010 - 12:48
Quote
Hibernate 3.5.1 не поддерживает @Inheritance (наследование) для интерфейсов. А я надеялся решить проблему множественного наследования для сущьностей.
В документации так и написано: “Annotating interfaces is currently not supported.”
Кто нибудь знает как быть с простым множественным наследованием в Hibernate?
interface FooAble {
get/setFooProp1
get/setFooProp2
}
interface BarAble {
get/setBarProp1
get/setBarProp2
}
class FooBarMaster implements FooAble, BarAble {
get/setFooProp1
get/setFooProp2
get/setBarProp1
get/setBarProp2
get/setFooBarMasterProp1
get/setFooBarMasterProp2
}
#4 by Дмитрий Леонтьев on 13 Сентябрь 2010 - 14:47
Quote
Васильевич, ссылку на оригинал добавил. Спасибо за напоминание.
Cyril Karpenko, действительно, про эту фичу не написал, но это не моя статья, а перевод. Критерии – интересная тема. Надо будет как-нибудь написать о них статью.
Semyon Goryachkin, не совсем Ваш вопрос. У вас интерфесы здесь, а это не наследование.
#5 by Armen on 6 Октябрь 2010 - 17:53
Quote
ja dumaju mnojestvennoe nasledovanie ni k chemu v java.