Двусторонняя связь между сущностями в Hibernate
Last updated: 11 мая 2025 г.Связь между объектами таблиц была односторонняя, то есть через объект Author
удалялся из БД или сохранялся в БД связанный объект AuthorInfo
.
Теперь сделаем наоборот. Так, чтобы через объект AuthorInfo производились какие-то действия в БД со связанным объектом Author.
Теперь уже будет двухсторонняя связь. То есть мы, например, можем совершить выборку из базы с помощью метода get объекта AuthorInfo
, и при этом автоматически будет получен из базы связанный с ним объект Author
.
Для двусторонней связности объектов связанных строк, необходимо изменить класс AuthorInfo
.
1package HibernateApps;
2
3import javax.persistence.CascadeType;
4import javax.persistence.Entity;
5import javax.persistence.GeneratedValue;
6import javax.persistence.GenerationType;
7import javax.persistence.Id;
8import javax.persistence.Column;
9import javax.persistence.OneToOne;
10import javax.persistence.Table;
11
12// Это класс с таблицы author_info.
13@Entity
14@Table(name = "author_info")
15public class AuthorInfo {
16
17 @Id
18 @GeneratedValue(
19 strategy = GenerationType.IDENTITY
20 )
21 @Column(name = "id")
22 private int id;
23
24 @Column(name = "books_written_number")
25 private int booksWritten;
26
27 @Column(name = "country")
28 private String country;
29
30 // Для двусторонней связанности указываем
31 // в mappedBy каким полем класс Author
32 // связан с данным классом AuthorInfo.
33 @OneToOne(mappedBy = "authorInfo",
34 cascade = CascadeType.ALL)
35 private Author author;
36
37 public AuthorInfo() {
38 }
39
40 public AuthorInfo(int booksWritten,
41 String country) {
42 this.booksWritten = booksWritten;
43 this.country = country;
44 }
45
46 public int getId() {
47 return id;
48 }
49
50 public void setId(int id) {
51 this.id = id;
52 }
53
54 public int getBooksWritten() {
55 return booksWritten;
56 }
57
58 public void setBooksWritten(
59 int booksWritten) {
60 this.booksWritten = booksWritten;
61 }
62
63 public String getCountry() {
64 return country;
65 }
66
67 public void setCountry(String country) {
68 this.country = country;
69 }
70
71 public Author getAuthor() {
72 return author;
73 }
74
75 public void setAuthor(Author author) {
76 this.author = author;
77 // В прошлом уроке мы передавали
78 // объект AuthorInfo в сеттер
79 // объекта Author для того чтобы эти
80 // объекты были связаны как связаны
81 // строки этих объектов в БД.
82 // Чтобы можно было так связать
83 // эти объекты наоборот, то есть
84 // в сеттер объекта Author
85 // передать объект Author,
86 // нужно еще и передать
87 // текущий(this) объект AuthorInfo
88 // объекту Author потому что если
89 // этого не сделать то объект Author
90 // не будет знать ничего
91 // о объекте AuthorInfo.
92
93 // Уточним что класс, в котором
94 // mappedBy не связан с тем, в котором
95 // JoinColumn напрямую. Связанным напрямую
96 // с другим классом можно назвать класс,
97 // в котором JoinColumn. Поэтому обратную
98 // связанность мы скорее имитируем
99 // использованием mappedBy
100 // и конструкциями типа
101 // author.setAuthorInfo(this);
102 author.setAuthorInfo(this);
103 }
104
105 @Override
106 public String toString() {
107 return "AuthorInfo [id=" + id + ", "
108 + "booksWritten="
109 + booksWritten + ", country="
110 + country + ", author="
111 + author + "]";
112 }
113}
Теперь давайте создадим два объекта, свяжем их теперь уже используя сеттер объекта AuthorInfo
и добавим их в БД.
1package HibernateApps;
2
3import org.hibernate.Session;
4import org.hibernate.SessionFactory;
5import org.hibernate.cfg.Configuration;
6
7public class HibernateApp {
8
9 public static void main(String[] args) {
10
11 // create session factory
12 SessionFactory factory = new Configuration()
13 .configure("hibernate.cfg.xml")
14 .addAnnotatedClass(Author.class)
15 .addAnnotatedClass(AuthorInfo.class)
16 .addAnnotatedClass(AuthorBooks.class)
17 .buildSessionFactory();
18
19 // create session
20 Session session = factory.getCurrentSession();
21
22 try {
23
24 session.beginTransaction();
25
26 //создадим два объекта и свяжем их
27 //только через сеттер объекта
28 //authorInfo, а не author как
29 //в прошлых уроках
30
31 AuthorInfo authorInfo = new AuthorInfo(10, "Great Britain");
32 Author author = new Author("JJ Rowling");
33
34 //связываем
35 authorInfo.setAuthor(author);
36
37 //при сохранении authorInfo сохраниться
38 //в базу и author поскольку они связаны
39
40 session.save(authorInfo);
41
42 AuthorInfo authorInfo1 = session.get(AuthorInfo.class, 1);
43 System.out.println(authorInfo1);
44
45 //строкой ниже удаляться связанные строки
46 //таблиц через связанные объекты этих строк.
47 session.delete(authorInfo1);
48
49 AuthorInfo authorInfo2 = session.get(AuthorInfo.class, 1);
50 System.out.println(authorInfo2);
51
52 session.getTransaction().commit();
53
54 }
55 catch (Exception e){
56 session.getTransaction().rollback();
57 e.printStackTrace();
58 }
59
60 finally {
61 session.close();
62 }
63
64 }
65}
Давайте запустим нашу программу.

Как видим, произошло два запроса на вставку, хотя метод save
мы вызывали только над одним объектом actorinfo
. Это доказывает, что каскадная PERSIST операция сработала и произошел insert
не только объекта authorinfo в таблицу author_info, а и связанного с ним объекта author в таблицу author. То есть двусторонняя связь работает.
Далее с помощью get мы выбрали из таблицы author_info только что положенную туда строку и поместили ее в объект authorinfo1
, в консоли можно увидеть содержимое объекта authorinfo1
, и как видим он, содержит объект author
, то есть опять таки, для выборки связь тоже работает.
После удаления из базы связанных объектов на консоль вывелось null
, значит объекты успешно удалились из базы.
Проверим на всякий случай и базу удалились ли обе строки в таблицах:

Следующие уроки
Настройка связи Один-ко-Многим в Hibernate
20
мин.
Типы извлечения данных в Hibernate (fetch types)
19
мин.
Настройка связи Многие-ко-Многим в Hibernate приложении
20
мин.