Настройка связи Многие-ко-Многим в Hibernate приложении
Last updated: 11 мая 2025 г.Теперь настроим в нашем приложении связь Многие-ко-Многим.
Пусть теперь в нашем приложении будет еще одна новая таблица – "Издательство"
.
Эта таблица будет связана с ранее созданной таблицей "Книги автора"
.
Любая книжка может быть напечатана несколькими издательствами и любое издательство может печатать какие-угодно книги.
То есть связь многие книги ко многим издательствам.
Ясное дело, при удалении издательства из таблицы publisher
не должны удаляться связанные с этим издательством книги в таблице author_books
, поскольку эти книги могут быть связаны и с другими издательствами.
И наоборот тоже – удаление книги не должно приводить к удалению связанных с ней издательств.
Поэтому и в классе таблицы publisher
и в классе таблицы author_books
необходимо исключить CascadeType=REMOVE.
Сделаем это.

Создадим теперь с помощью sql запроса таблицу publisher
в которой будут храниться издательства.
Кто знает базы данных должен знать, что связь многие ко многим между двумя таблицами реализуется с помощью промежуточной таблицы, где есть два столбца – id
издательства и id
книги. Создадим эту таблицу.

Теперь создадим класс созданной только что таблицы publisher
. И настроим связь Многие-ко-Многим между этим классом и классом AuthorBooks
через промежуточную таблицу.
1package HibernateApps;
2
3import java.util.ArrayList;
4
5import javax.persistence.*;
6
7@Entity
8@Table(name = "publisher")
9public class Publisher {
10
11 @Id
12 @GeneratedValue(strategy=GenerationType.IDENTITY)
13 @Column(name="id")
14 private int id;
15
16 @Column(name="name")
17 private String publisherName;
18
19 //Теперь используем аннотацию
20 //@ManyToMany (Многие-ко-многим).
21 //многие Publisher ко многим AuthorBooks.
22 //Важно убрать CascadeType.REMOVE чтобы
23 //при удалении из БД какой-то из книги
24 //не удалялись из БД издательства
25 @ManyToMany(cascade = {CascadeType.DETACH,
26 CascadeType.REFRESH,
27 CascadeType.PERSIST,
28 CascadeType.MERGE})
29 //Теперь настраиваем связи таблицы publisher
30 //с таблицей author_books через промежуточную
31 //таблицу author_books_publisher.
32 @JoinTable(
33 Имя промежуточной таблицы.
34 name = "authours_books_publisher",
35 //Указываем название атрибута
36 //промежуточной таблицы в котором
37 //хранятся идентификаторы строк
38 //из таблицы publisher.
39 joinColumns=@JoinColumn(name="publisher_id"),
40 //Указываем название атрибута
41 //промежуточной таблицы в котором
42 //хранятся идентификаторы строк
43 //из таблицы author_books.
44 inverseJoinColumns=@JoinColumn(name="authorbook_id"))
45 private List<AuthorBooks> authorbook;
46
47
48 public Publisher() {
49 }
50
51 public Publisher(String publisherName) {
52 this.publisherName = publisherName;
53 }
54
55 public int getId() {
56 return id;
57 }
58
59 public void setId(int id) {
60 this.id = id;
61 }
62
63 public String getPublisherName() {
64 return publisherName;
65 }
66
67 public void setPublisherName(
68 String publisherName) {
69 this.publisherName = publisherName;
70 }
71
72 public List<AuthorBooks> getAuthorbook() {
73 return authorbook;
74 }
75
76 public void setAuthorbook(
77 List<AuthorBooks> authorbook) {
78 this.authorbook = authorbook;
79 }
80
81 //Для связывания объекта книги
82 //с объектом издательства просто
83 //добавляем объект книги в List
84 //объекта издательства. Тогда при
85 //добавлении в БД издательства, через
86 //объект издательства добавляются в БД
87 //и книги находящиеся в List
88 //в этом объекте издательства.
89 public void setOneBook(
90 AuthorBooks authorbook){
91 if (this.authorbook==null) {
92 this.authorbook = new ArrayList<>();
93 }
94 this.authorbook.add(authorbook);
95 }
96
97
98 @Override
99 public String toString() {
100 return "Publisher [id=" + id
101 + ", publisherName="
102 + publisherName
103 + ", authorbook="
104 + authorbook + "]";
105 }
106}
Теперь в классе таблицы author_books
настроим связь Многие-ко-Многим между этим классом и классом Publisher
также через промежуточную таблицу.
Связь настраивается таким же образом как и в классе Publisher
, только меняем местами publisher_id
и authorbook_id
1package HibernateApps;
2
3import java.util.ArrayList;
4import java.util.List;
5
6import javax.persistence.CascadeType;
7import javax.persistence.Column;
8import javax.persistence.Entity;
9import javax.persistence.GeneratedValue;
10import javax.persistence.GenerationType;
11import javax.persistence.Id;
12import javax.persistence.JoinColumn;
13import javax.persistence.JoinTable;
14import javax.persistence.ManyToMany;
15import javax.persistence.ManyToOne;
16import javax.persistence.Table;
17
18
19@Entity
20@Table(name = "author_books")
21public class AuthorBooks {
22
23 @Id
24 @GeneratedValue(
25 strategy=GenerationType.IDENTITY
26 )
27 @Column(name="id")
28 private int id;
29
30 @Column(name="name")
31 private String bookName;
32
33 @ManyToOne(cascade ={CascadeType.DETACH,
34 CascadeType.REFRESH,
35 CascadeType.PERSIST,
36 CascadeType.MERGE})
37 @JoinColumn(name="author_id")
38 private Author author;
39
40 //Также используем аннотацию
41 //@ManyToMany (Многие-ко-Многим).
42 //Многие AuthorBooks ко многим Publisher.
43 //Важно убрать CascadeType.REMOVE чтобы
44 //при удалении из БД какого-то из издательств
45 //не удалялись из БД книги напечатанные им.
46 @ManyToMany(cascade ={CascadeType.DETACH,
47 CascadeType.REFRESH,
48 CascadeType.PERSIST,
49 CascadeType.MERGE})
50 @JoinTable(name="authorbooks_publisher",
51 //Связь с таблицей publisher
52 //через промежуточную таблицу
53 //в этом классе настраиваем также
54 //как и в классе Publisher только
55 //как можно увидеть ниже
56 //в joinColumns теперь authorbook_id,
57 //а в inverseJoinColumns
58 //теперь publisher_id.
59 joinColumns=
60 @JoinColumn(name="authorbook_id"),
61 inverseJoinColumns=
62 @JoinColumn(name="publisher_id"))
63 private List<Publisher> publisher;
64
65
66 public AuthorBooks () {
67 }
68
69 public AuthorBooks(String bookName) {
70 this.bookName = bookName;
71 }
72
73
74 public int getId() {
75 return id;
76 }
77
78 public void setId(int id) {
79 this.id = id;
80 }
81
82 public String getBookName() {
83 return bookName;
84 }
85
86 public void setBookName(String bookName) {
87 this.bookName = bookName;
88 }
89
90 public Author getAuthor() {
91 return author;
92 }
93
94 public void setAuthor(Author author) {
95 this.author = author;
96 }
97
98 @Override
99 public String toString() {
100 return "Book [id="
101 + id + ", bookName="
102 + bookName + "]";
103 }
104}
Пример программы со связью Многие-ко-Многим:
1package HibernateApps;
2
3import org.hibernate.Session;
4import org.hibernate.SessionFactory;
5import org.hibernate.cfg.Configuration;
6
7public class HibernateApp {
8 public static void main(String[] args) {
9 //Добавим Publisher в sessionfactory
10 SessionFactory sessionFactory = new Configuration()
11 .configure("hibernate.cfg.xml")
12 .addAnnotatedClass(Author.class)
13 .addAnnotatedClass(AuthorInfo.class)
14 .addAnnotatedClass(AuthorBooks.class)
15 .addAnnotatedClass(Publisher.class)
16 .buildSessionFactory();
17
18 Session session = sessionFactory.getCurrentSession();
19
20 try {
21 session.beginTransaction();
22 //создаем издательства
23 Publisher publisher = new Publisher("Yakaboo");
24 Publisher publisher1 = new Publisher("Vivat");
25 Publisher publisher2 = new Publisher("IPIO");
26 //извлем три книги из БД
27 AuthorBooks authorbook =
28 session.get(AuthorBooks.class,1);
29 AuthorBooks authorbook1 =
30 session.get(AuthorBooks.class,2);
31 AuthorBooks authorbook2 =
32 session.get(AuthorBooks.class,3);
33
34 //Связываем первое издательство
35 //с первой и третьей книгой.
36 publisher.setOneBook(authorbook);
37 publisher.setOneBook(authorbook2);
38 //Связываем второе издательство
39 //с первой, второй и третьей книгой.
40 publisher1.setOneBook(authorbook);
41 publisher1.setOneBook(authorbook1);
42 publisher1.setOneBook(authorbook2);
43 //Связываем третье издательство
44 //со второй и третьей книгой.
45 publisher2.setOneBook(authorbook1);
46 publisher2.setOneBook(authorbook2);
47 //сохраняем издательства в базу
48 session.save(publisher);
49 session.save(publisher1);
50 session.save(publisher2);
51 session.getTransaction().commit();
52
53 } catch (Exception e) {
54 session.getTransaction().rollback();
55 e.printStackTrace();
56 } finally{
57 session.close();
58 }
59 }
60}
Давайте запустим нашу программу.

Как видим, сначала произошло три select запроса на выборку книг (как мы помним, мы извлекали из БД три книги с помощью get
).
Далее произошла вставка (insert
) трех издательств в таблицу publisher
и потом произошло связывание издательств и книжек посредством вставки идентификаторов в промежуточную таблицу.

Как видим, вставка издательств в таблицу publisher
произошла успешно. Можно убедиться, что в промежуточной таблице книги и издательства связаны в соответствии с тем как мы их связывали в программе
Дополнительные материалы
Следующие уроки
Сборщик проектов Maven
17
мин.
Создание Maven веб-проекта в Eclipse IDE
16
мин.
Настройка файла pom.xml в Maven
20
мин.