В прошлом посте мы создали простое приложение которое работает с базой данных через фреймворк hibernate. В этом посте создаваемая нами программа будет делать все тоже самое, только для конфигурирования сущностных классов будем использовать не xml файлы с расширением hbm.xml, а добавим конфигурацию в сами сущностные классы в виде аннотаций. Так же в этом посте для сборки приложения мы воспользуемся мавеном, так как сборка проекта из терминала хорошо описана в предыдущем посте.
Похожие посты
Что нам потребуется
Весь проект можно взять с gitHub: https://github.com/dev-blogs/hibernate-with-annotations
База данных
База данных в этом посте точно такая же как в посте Работа с базой данных через JDBC. Там приводится ее структура и как ее поднять в MySQL. Для экономии места в этом посте я эти детали не привожу. Кто собирается все это дело компилировать и запускать, то убедитесь, что у вас установлена MySQL и засетаплена соответствующая база из того поста.
Структура проекта
Создайте мавенский проект представленной ниже структуры:
hibernate-annotation ├──src │ ├─main │ │ ├─java │ │ │ ├─com │ │ │ │ └─dev │ │ │ │ └─blogs │ │ │ │ └─hibernate │ │ │ │ ├─App.java │ │ │ │ └─Factory.java │ │ │ ├─dao │ │ │ │ ├─ItemDAO.java │ │ │ │ ├─ProviderDAO │ │ │ │ └─WarehouseDAO │ │ │ ├─daoImpl │ │ │ │ ├─ItemDAOImpl.java │ │ │ │ ├─ProviderDAOImpl.java │ │ │ │ └─WarehouseDAOImpl.java │ │ │ ├─model │ │ │ │ ├─Item.java │ │ │ │ ├─Provider.java │ │ │ │ └─Warehouse.java │ │ │ └─util │ │ │ └─HibernateUtil.java │ │ ├─resources │ │ │ └─hibernate.cfg.xml │ │ └─scripts │ │ ├─create-data-model.sql │ │ └─fill-database.sql │ └─test │ └─java │ └─com │ └─dev │ └─blogs │ └─hibernate │ └─AppTest.java └──pom.xml
Добавляем java код
Добавим сущностные классы, в которые добавим соответствующие аннотации отображения.
Warehouse.java
package model; import java.util.HashSet; import java.util.Set; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.FetchType; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.OneToMany; import javax.persistence.Table; @Entity @Table(name = "warehouses") public class Warehouse { @Id @GeneratedValue(strategy = GenerationType.AUTO) @Column(name = "id") private Long id; @Column(name = "address") private String address; @OneToMany(fetch = FetchType.LAZY, mappedBy = "warehouse") private Set<Item> items = new HashSet<Item>(); public Warehouse() { } public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getAddress() { return address; } public void setAddress(String address) { this.address = address; } public Set<Item> getItems() { return items; } public void setItems(Set<Item> items) { this.items = items; } }
Item.java
package model; import java.util.HashSet; import java.util.Set; import javax.persistence.CascadeType; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.FetchType; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.JoinColumn; import javax.persistence.JoinTable; import javax.persistence.ManyToMany; import javax.persistence.ManyToOne; import javax.persistence.Table; @Entity @Table(name = "items") public class Item { @Id @GeneratedValue(strategy = GenerationType.AUTO) @Column(name = "id") private Long id; @Column(name = "name") private String name; @ManyToMany(fetch = FetchType.EAGER, cascade = {CascadeType.ALL}) @JoinTable(name = "items_providers", joinColumns={@JoinColumn(name = "item_id")}, inverseJoinColumns={@JoinColumn(name = "provider_id")}) private Set<Provider> providers = new HashSet<Provider>(); @ManyToOne @JoinColumn(name = "warehouse_id") private Warehouse warehouse; public Item() { } public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Set<Provider> getProviders() { return providers; } public void setProviders(Set<Provider> providers) { this.providers = providers; } public Warehouse getWarehouse() { return warehouse; } public void setWarehouse(Warehouse warehouse) { this.warehouse = warehouse; } }
Provider.java
package model; import java.util.HashSet; import java.util.Set; import javax.persistence.CascadeType; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.FetchType; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.JoinColumn; import javax.persistence.JoinTable; import javax.persistence.ManyToMany; import javax.persistence.Table; @Entity @Table(name = "providers") public class Provider { @Id @GeneratedValue(strategy = GenerationType.AUTO) @Column(name = "id") private Long id; @Column(name = "name") private String name; @ManyToMany(fetch = FetchType.EAGER, cascade = {CascadeType.ALL}) @JoinTable(name = "items_providers", joinColumns={@JoinColumn(name = "provider_id")}, inverseJoinColumns={@JoinColumn(name = "item_id")}) private Set<Item> items = new HashSet<Item>(); public Provider() { } public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Set<Item> getItems() { return items; } public void setItems(Set<Item> items) { this.items = items; } }
Аннотации в сущностном классе
Теперь опишем какие аннотации за что отвечают и о чем они говорят хибернейту.
- Аннотация @Entity. Каждый класс в самом начале мы про аннотировали аннотацией @Entity. Эта аннотация говорит хибернейту о том, что это отображенный сущностный класс.
- Аннотация @Table. Аннотация @Table, следующая за ней, определяет имя таблицы в базе данных, на которую эта сущность мапится.
- Аннотация @Column. Каждое поле в классе (вместо этого можно его гет-метод) проаннотировано аннотацией @Column, который указывает имя столбца в таблице, на который это поле мапится.
- Аннотации @Id и @GeneratedValue. Особое внимание на поле Id. Оно (или его гет-метод) аннотируется с помощью аннотации @Id, что значит, что это поле является первичным ключом. Так как в базе данных первичный ключ у нас объявлен как AUTO_INCREMENT, это значит, увеличение айдишника первичного ключа мы переложили на СУРБД, то сообщим об этом хибернейту аннотацией @GeneratedValue(strategy = GenerationType.AUTO) сразу за аннотацией @Id. Стратегия GenerationType.AUTO означает, что его значение будет генерироваться и назначаться базой данных при выполнении операции вставки.
- Аннотация @OneToMany. Таблица warehouses связана с таблицей items отношением один ко многим. В сущностных классах это выражается аннотацией @OneToMany. В классе Warehouse поле items помечено аннотацией @OneToMany(fetch = FetchType.LAZY, mappedBy = «warehouse»), это значит, что на один объект Warehouse приходится ноль или более объектов Item, атрибут mappedBy задает свойство в классе Item, которое представляет ассоциацию, то есть является внешним ключом в таблице items, а атрибут fetch определяет характер выборки для вложенных объектов, то есть нужно ли их подтягивать из базы только при явном обращении к ним (свойство FetchType.LAZY) или всегда (свойство FetchType.EAGER). В первом случае экономиться память, но увеличивается время доступа к вложенным объектам
- Аннотация @ManyToOne и @JoinColumn. Таблица items наоборот связана с таблицей warehouses отношением много к одному. В сущностном классе Item это выражается аннотацией @ManyToOne которая задает другую сторону ассоциации с Warehouse. В классе Item поле warehouse проаннотировано аннотацией @ManyToOne @JoinColumn(name = «warehouse_id»), что означает, что данное поле является внешним ключом, а аннотация @JoinColumn указывает имя столбца внешнего ключа.
- Аннотация @ManyToMany. А теперь добрались до самой сложной связки много ко многим. Таблица items связана с таблицей providers через промежуточную таблицу items_providers. Поле providers в классе Item проаннотировано аннотацией @ManyToMany.
- Аннотация @JoinTable указывает имя таблицы соединения, то есть имя промежуточной таблицы, которое указывается в атрибуте name
- Аннотация @joinColumns определяет столбец в промежуточной таблице, который является внешним ключом к таблице на которую мапится текущий класс
- Аннотация @inverseJoinColumns определяет столбец в промежуточной таблице, который является внешним ключом для другой стороны ассоциации, то есть для таблицы на которую мапится класс Provider
DAO слой
Аннотации касались только сущностных классов, далее все тоже самое, что и в предыдущем посте, кроме как тут не будет xml фалов отображения.
Опишем dao-классы, их интерфейсы и реализацию, тут вроде все просто.
ItemDAO.java
package dao; import java.sql.SQLException; import java.util.Collection; import model.Item; public interface ItemDAO { public void addItem(Item item) throws SQLException, Exception; public void updateItem(Item item) throws SQLException, Exception; public Item getItemById(Long id) throws SQLException, Exception; public Collection<Item> getAllItems() throws SQLException, Exception; public void deleteItem(Item item) throws SQLException, Exception; }
ProviderDAO.java
package dao; import java.sql.SQLException; import java.util.Collection; import model.Provider; public interface ProviderDAO { public void addProvider(Provider provider) throws SQLException, Exception; public void updateProvider(Provider provider) throws SQLException, Exception; public Provider getProviderById(Long id) throws SQLException, Exception; public Collection<Provider> getAllProviders() throws SQLException, Exception; public void deleteProvider(Provider provider) throws SQLException, Exception; }
WarehouseDAO.java
package dao; import java.sql.SQLException; import java.util.Collection; import model.Warehouse; public interface WarehouseDAO { public void addWarehouse(Warehouse warehouse) throws SQLException, Exception; public void updateWarehouse(Warehouse warehouse) throws SQLException, Exception; public Warehouse getWarehouseById(Long id) throws SQLException, Exception; public Collection<Warehouse> getAllWarehouses() throws SQLException, Exception; public void deleteWarehouse(Warehouse warehouse) throws SQLException, Exception; }
ItemDAOImpl.java
package daoImpl; import java.sql.SQLException; import java.util.ArrayList; import java.util.Collection; import java.util.List; import model.Item; import org.hibernate.Session; import util.HibernateUtil; import dao.ItemDAO; public class ItemDAOImpl implements ItemDAO { private Session session; public ItemDAOImpl() { session = HibernateUtil.getSessionFactory().openSession(); } public Collection<Item> getAllItems() throws SQLException, Exception { List<Item> items = new ArrayList<Item>(); items = session.createCriteria(Item.class).list(); return items; } public void addItem(Item item) throws SQLException, Exception { session.beginTransaction(); session.save(item); session.getTransaction().commit(); } public void updateItem(Item item) throws SQLException, Exception { session.beginTransaction(); session.update(item); session.getTransaction().commit(); } public Item getItemById(Long id) throws SQLException, Exception { Item item = null; item = (Item) session.load(Item.class, id); return item; } public void deleteItem(Item item) throws SQLException, Exception { session.beginTransaction(); session.delete(item); session.getTransaction().commit(); } }
ProviderDAOImpl.java
package daoImpl; import java.sql.SQLException; import java.util.ArrayList; import java.util.Collection; import java.util.List; import org.hibernate.Session; import dao.ProviderDAO; import model.Provider; import util.HibernateUtil; public class ProviderDAOImpl implements ProviderDAO { private Session session; public ProviderDAOImpl() { session = HibernateUtil.getSessionFactory().openSession(); } public void addProvider(Provider provider) throws SQLException, Exception { session.beginTransaction(); session.save(provider); session.getTransaction().commit(); } public void updateProvider(Provider provider) throws SQLException, Exception { session.beginTransaction(); session.update(provider); session.getTransaction().commit(); } public Provider getProviderById(Long id) throws SQLException, Exception { Provider provider = null; provider = (Provider) session.load(Provider.class, id); return provider; } public Collection<Provider> getAllProviders() throws SQLException, Exception { List<Provider> providers = new ArrayList<Provider>(); providers = session.createCriteria(Provider.class).list(); return providers; } public void deleteProvider(Provider provider) throws SQLException, Exception { session.beginTransaction(); session.delete(provider); session.getTransaction().commit(); } }
WarehouseDAOImpl.java
package daoImpl; import java.sql.SQLException; import java.util.ArrayList; import java.util.Collection; import java.util.List; import org.hibernate.Session; import util.HibernateUtil; import model.Warehouse; import dao.WarehouseDAO; public class WarehouseDAOImpl implements WarehouseDAO { private Session session; public WarehouseDAOImpl() { session = HibernateUtil.getSessionFactory().openSession(); } public void addWarehouse(Warehouse warehouse) throws SQLException, Exception { session.beginTransaction(); session.save(warehouse); session.getTransaction().commit(); } public void updateWarehouse(Warehouse warehouse) throws SQLException, Exception { session.beginTransaction(); session.update(warehouse); session.getTransaction().commit(); } public Warehouse getWarehouseById(Long id) throws SQLException, Exception { Warehouse warehouse = null; warehouse = (Warehouse) session.load(Warehouse.class, id); return warehouse; } public Collection<Warehouse> getAllWarehouses() throws SQLException, Exception { List<Warehouse> warehouses = new ArrayList<Warehouse>(); warehouses = session.createCriteria(Warehouse.class).list(); return warehouses; } public void deleteWarehouse(Warehouse warehouse) throws SQLException, Exception { session.beginTransaction(); session.delete(warehouse); session.getTransaction().commit(); } }
Factory.java
Объект фабрика будет создавать и возвращать объекты dao-слоя.
package com.dev.blogs.hibernate; import dao.ItemDAO; import dao.ProviderDAO; import dao.WarehouseDAO; import daoImpl.ItemDAOImpl; import daoImpl.ProviderDAOImpl; import daoImpl.WarehouseDAOImpl; public class Factory { private static Factory instance = null; private static ItemDAO itemDAO = null; private static ProviderDAO providerDAO = null; private static WarehouseDAO warehouseDAO = null; public static synchronized Factory getInstance() { if (instance == null) { instance = new Factory(); } return instance; } public ItemDAO getItemDAO() { if (itemDAO == null) { itemDAO = new ItemDAOImpl(); } return itemDAO; } public ProviderDAO getProviderDAO() { if (providerDAO == null) { providerDAO = new ProviderDAOImpl(); } return providerDAO; } public WarehouseDAO getWarehouseDAO() { if (warehouseDAO == null) { warehouseDAO = new WarehouseDAOImpl(); } return warehouseDAO; } }
HibernateUtil.java
Класс HibernateUtil.java создает и возвращает фабрику сессий по шаблону синглетон, гарантируя, что инстанс фабрики будет один на протяжении всего выполнения приложения.
package util; import org.hibernate.SessionFactory; import org.hibernate.cfg.Configuration; public class HibernateUtil { private static final SessionFactory sessionFactory; static { try { sessionFactory = new Configuration().configure().buildSessionFactory(); } catch (Throwable e) { System.err.println("Initial SessionFactory creation failed. " + e); throw new ExceptionInInitializerError(e); } } public static SessionFactory getSessionFactory() { return sessionFactory; } }
App.java этот класс с которого будет запускаться приложение.
App.java
package com.dev.blogs.hibernate; import java.sql.SQLException; import java.util.Collection; import java.util.Iterator; import java.util.Set; import model.Item; import model.Provider; import model.Warehouse; import org.hibernate.Session; public class App { public void printAllWarehouses() { Session session = null; try { Collection<Warehouse> warehouses = Factory.getInstance().getWarehouseDAO().getAllWarehouses(); Iterator<Warehouse> warehouseIterator = warehouses.iterator(); System.out.println("list of warehouses:"); while (warehouseIterator.hasNext()) { Warehouse warehouse = (Warehouse) warehouseIterator.next(); System.out.println("warehouse number " + warehouse.getId() + ", address is " + warehouse.getAddress()); Collection<Item> items = warehouse.getItems(); Iterator<Item> itemIterator = items.iterator(); while (itemIterator.hasNext()) { Item item = (Item) itemIterator.next(); System.out.println(" has " + item.getName() + ", id of this item is " + item.getId()); Set<Provider> providers = item.getProviders(); Iterator<Provider> providerIterator = providers.iterator(); while (providerIterator.hasNext()) { Provider provider = (Provider) providerIterator.next(); System.out.println(" which is provided by " + provider.getName() + ", id of this provider is " + provider.getId()); } } System.out.println(); } } catch (SQLException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } finally { if (session != null && session.isOpen()) { session.close(); } } } }
AppTest.java
Это даже тестом не назовешь, просто для наглядности, чтобы увидеть вывод.
package com.dev.blogs.hibernate; import org.junit.Test; public class AppTest { @Test public void testApp() { App app = new App(); app.printAllWarehouses(); } }
В файле hibernate.cfg.xml пропишем всю необходимые хибернейту конфигурацию, какая будет использоваться база, какой логин и пароль к этой базе и пр.
hibernate.cfg.xml
<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd"> <hibernate-configuration> <session-factory> <property name="connection.url">jdbc:mysql://localhost/warehouse</property> <property name="connection.driver_class">com.mysql.jdbc.Driver</property> <property name="connection.username">user</property> <property name="connection.password">password</property> <property name="connection.pool_size">1</property> <property name="current_session_context_class">thread</property> <property name="dialect">org.hibernate.dialect.MySQL5Dialect</property> <!--<property name="show_sql">true</property>--> <!--<property name="format_sql">true</property>--> <mapping class="model.Warehouse"/> <mapping class="model.Item"/> <mapping class="model.Provider"/> </session-factory> </hibernate-configuration>
Билд скрипт
pom.xml
<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/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.dev.blogs</groupId> <artifactId>hibernate-annotation</artifactId> <version>1.0-SNAPSHOT</version> <packaging>jar</packaging> <name>hibernate-annotation</name> <url>http://maven.apache.org</url> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> </properties> <dependencies> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-core</artifactId> <version>3.6.3.Final</version> </dependency> <dependency> <groupId>javassist</groupId> <artifactId>javassist</artifactId> <version>3.12.1.GA</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.6</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.11</version> <scope>test</scope> </dependency> </dependencies> </project>
Сборка проекта и запуск проекта
Теперь все что надо сделать это запустить командочку mvn test и мавен соберет проект и прогонит тесты:
mvn test [INFO] Scanning for projects... [INFO] [INFO] ------------------------------------------------------------------------ [INFO] Building hibernate-annotation 1.0-SNAPSHOT [INFO] ------------------------------------------------------------------------ [INFO] [INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ hibernate-annotation --- [INFO] Using 'UTF-8' encoding to copy filtered resources. [INFO] Copying 1 resource [INFO] [INFO] --- maven-compiler-plugin:3.1:compile (default-compile) @ hibernate-annotation --- [INFO] Changes detected - recompiling the module! [INFO] Compiling 12 source files to /home/zheka/practice/1/hibernate-with-annotations/target/classes [WARNIN] /home/zheka/practice/1/hibernate-with-annotations/src/main/java/daoImpl/WarehouseDAOImpl.java: Some input files use unchecked or unsafe operations. [WARNIN] /home/zheka/practice/1/hibernate-with-annotations/src/main/java/daoImpl/WarehouseDAOImpl.java: Recompile with -Xlint:unchecked for details. [INFO] [INFO] --- maven-resources-plugin:2.6:testResources (default-testResources) @ hibernate-annotation --- [INFO] Using 'UTF-8' encoding to copy filtered resources. [INFO] skip non existing resourceDirectory /home/zheka/practice/1/hibernate-with-annotations/src/test/resources [INFO] [INFO] --- maven-compiler-plugin:3.1:testCompile (default-testCompile) @ hibernate-annotation --- [INFO] Changes detected - recompiling the module! [INFO] Compiling 1 source file to /home/zheka/practice/1/hibernate-with-annotations/target/test-classes [INFO] [INFO] --- maven-surefire-plugin:2.12.4:test (default-test) @ hibernate-annotation --- [INFO] Surefire report directory: /home/zheka/practice/1/hibernate-with-annotations/target/surefire-reports ------------------------------------------------------- T E S T S ------------------------------------------------------- Running com.dev.blogs.hibernate.AppTest SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder". SLF4J: Defaulting to no-operation (NOP) logger implementation SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details. list of warehouses: warehouse number 1, address is ul. one, 5 has red chair, id of this item is 5 which is provided by Sasha, id of this provider is 3 has black chair, id of this item is 4 which is provided by Vasya, id of this provider is 1 has green plates, id of this item is 11 which is provided by Petya, id of this provider is 2 has red plates, id of this item is 12 which is provided by Vasya, id of this provider is 1 has yellow chair, id of this item is 8 which is provided by Vasya, id of this provider is 1 has black plates, id of this item is 10 which is provided by Petya, id of this provider is 2 has blue chair, id of this item is 6 which is provided by Vasya, id of this provider is 1 has green chair, id of this item is 7 which is provided by Sasha, id of this provider is 3 which is provided by Petya, id of this provider is 2 which is provided by Vasya, id of this provider is 1 has grey plates, id of this item is 14 which is provided by Petya, id of this provider is 2 has red table, id of this item is 1 which is provided by Sasha, id of this provider is 3 which is provided by Vasya, id of this provider is 1 has yellow plates, id of this item is 13 which is provided by Sasha, id of this provider is 3 has white chair, id of this item is 9 which is provided by Vasya, id of this provider is 1 has blue table, id of this item is 2 which is provided by Petya, id of this provider is 2 has green table, id of this item is 3 which is provided by Petya, id of this provider is 2 warehouse number 3, address is ul. three, 7 has white sofa, id of this item is 38 which is provided by Vasya, id of this provider is 1 has white cupboard, id of this item is 39 which is provided by Vasya, id of this provider is 1 has blue cupboard, id of this item is 41 which is provided by Sasha, id of this provider is 3 has yellow blinds, id of this item is 28 which is provided by Vasya, id of this provider is 1 has brown blinds, id of this item is 33 which is provided by Sasha, id of this provider is 3 has yellow sofa, id of this item is 36 which is provided by Sasha, id of this provider is 3 has black sofa, id of this item is 37 which is provided by Sasha, id of this provider is 3 has black blinds, id of this item is 31 which is provided by Vasya, id of this provider is 1 has red cupboard, id of this item is 40 which is provided by Sasha, id of this provider is 3 has red blinds, id of this item is 29 which is provided by Vasya, id of this provider is 1 has white blinds, id of this item is 32 which is provided by Sasha, id of this provider is 3 has green cupboard, id of this item is 42 which is provided by Vasya, id of this provider is 1 has grey sofa, id of this item is 34 which is provided by Petya, id of this provider is 2 has red sofa, id of this item is 35 which is provided by Petya, id of this provider is 2 has green blinds, id of this item is 30 which is provided by Sasha, id of this provider is 3 warehouse number 2, address is ul. two, 4 has grey spoon, id of this item is 18 which is provided by Vasya, id of this provider is 1 has black fork, id of this item is 24 which is provided by Petya, id of this provider is 2 has yellow fork, id of this item is 22 which is provided by Vasya, id of this provider is 1 has large scissors, id of this item is 15 which is provided by Vasya, id of this provider is 1 has brown fork, id of this item is 27 which is provided by Sasha, id of this provider is 3 has green spoon, id of this item is 19 which is provided by Sasha, id of this provider is 3 has yellow spoon, id of this item is 20 which is provided by Sasha, id of this provider is 3 has red fork, id of this item is 23 which is provided by Petya, id of this provider is 2 has green fork, id of this item is 25 which is provided by Vasya, id of this provider is 1 has red spoon, id of this item is 17 which is provided by Sasha, id of this provider is 3 has white spoon, id of this item is 21 which is provided by Sasha, id of this provider is 3 has blue fork, id of this item is 26 which is provided by Petya, id of this provider is 2 has small scissors, id of this item is 16 which is provided by Vasya, id of this provider is 1 Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.865 sec Results : Tests run: 1, Failures: 0, Errors: 0, Skipped: 0 [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ [INFO] Total time: 2.569 s [INFO] Finished at: 2016-04-19T22:25:45+03:00 [INFO] Final Memory: 15M/163M [INFO] ------------------------------------------------------------------------
После запуска тестов, мы должны увидеть полный вывод базы данных.
Линки
Hibernate – One-to-Many example (Annotation)
Hibernate One to Many Mapping (Annotation) Example
Hibernate Many To Many Annotation Mapping Tutorial
Hibernate One To Many Annotation tutorial