Hibernate(十):n-n关联关系

  • 背景:

  在实际开发中我们会遇到表的多对多关联,比如:一篇博客文章,它可以同时属于JAVA分类、Hibernate分类。

  因此,我们在hibernate的学习文章系列中,需要学会如何使用hibernate来实现多对多的关联关系。

  在hibernate实现多对多的关联关系中,也是需要创建一个中间表来存储、维护两张表的多对多的关系。具体实现有两种可选方案:单向多对多、双向多对多。

  • 单向多对多:

 新建一个java project,定义项目名称为:hibernate07;在src下添加hibernate.cfg.xml

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <!DOCTYPE hibernate-configuration PUBLIC
 3         "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
 4         "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
 5 <hibernate-configuration>
 6     <session-factory>
 7         <property name="hibernate.connection.username">root</property>
 8         <property name="hibernate.connection.password">123456</property>
 9         <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
10         <property name="hibernate.connection.url">jdbc:mysql://localhost/hibernate_01</property>
11 
12         <!-- <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property> 
13             <property name="hibernate.dialect">org.hibernate.dialect.MySQLInnoDBDialect</property> -->
14         <property name="hibernate.dialect">org.hibernate.dialect.MySQL5InnoDBDialect</property>
15 
16         <property name="hibernate.show_sql">true</property>
17 
18         <property name="hibernate.format_sql">true</property>
19 
20         <property name="hibernate.hbm2ddl.auto">update</property>
21 
22         <property name="hibernate.current_session_context_class">thread</property>
23 
24         <property name="hibernate.c3p0.max_size">500</property>
25         <property name="hibernate.c3p0.min_size">20</property>
26         <property name="hibernate.c3p0.max_statements">10</property>
27         <property name="hibernate.c3p0.timeout">2000</property>
28         <property name="hibernate.c3p0.idle_test_period">2000</property>
29         <property name="hibernate.c3p0.acquire_increment">10</property>
30 
31         <mapping resource="com/dx/hibernate06/n2n/ProductCategory.hbm.xml" />        
32         <mapping resource="com/dx/hibernate06/n2n/ProductItem.hbm.xml" />
33             
34     </session-factory>
35 </hibernate-configuration>
View Code

在src下创建包com.dx.hibernate06.n2n,在包下创建:

ProductCategory.java(在category这个类中创建了一个Set<ProductItem> productItems 属性)

 1 package com.dx.hibernate06.n2n;
 2 
 3 import java.util.HashSet;
 4 import java.util.Set;
 5 
 6 public class ProductCategory {
 7     private Integer id;
 8     private String name;
 9     private String detail;
10     private Set<ProductItem> productItems = new HashSet<>();
11 
12     public ProductCategory() {
13 
14     }
15 
16     public ProductCategory(String name, String detail) {
17         super();
18         this.name = name;
19         this.detail = detail;
20     }
21 
22     public Integer getId() {
23         return id;
24     }
25 
26     public void setId(Integer id) {
27         this.id = id;
28     }
29 
30     public String getName() {
31         return name;
32     }
33 
34     public void setName(String name) {
35         this.name = name;
36     }
37 
38     public String getDetail() {
39         return detail;
40     }
41 
42     public void setDetail(String detail) {
43         this.detail = detail;
44     }
45 
46     public Set<ProductItem> getProductItems() {
47         return productItems;
48     }
49 
50     public void setProductItems(Set<ProductItem> productItems) {
51         this.productItems = productItems;
52     }
53 
54 }
View Code

ProductCategory.hbm.xml

 1 <?xml version="1.0"?>
 2 <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
 3 "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
 4 <!-- Generated 2017-6-7 22:33:53 by Hibernate Tools 3.5.0.Final -->
 5 <hibernate-mapping package="com.dx.hibernate06.n2n">
 6     <class name="ProductCategory" table="PRODUCT_CATEGORY">
 7         <id name="id" type="java.lang.Integer">
 8             <column name="ID" />
 9             <generator class="native" />
10         </id>
11         <property name="name" type="java.lang.String">
12             <column name="NAME" />
13         </property>
14         <property name="detail" type="java.lang.String">
15             <column name="DETAIL" />
16         </property>
17 
18         <set name="productItems" table="PRODUCT_CATEGORY_ITEM">
19             <key>
20                 <column name="CATEGORY_ID" />
21             </key>
22             <many-to-many class="ProductItem" column="ITEM_ID"></many-to-many>
23         </set>
24     </class>
25 </hibernate-mapping>
View Code

备注:在ProductCategory.hbm.xml的set节点我们定义的table属性,并定义了many-to-many节点用来指向ProductItem。

ProductItem.java

 1 package com.dx.hibernate06.n2n;
 2 
 3 public class ProductItem {
 4     private Integer id;
 5     private String title;
 6     private double price;
 7 
 8     public ProductItem() {
 9     }
10 
11     public ProductItem(String title, double price) {
12         super();
13         this.title = title;
14         this.price = price;
15     }
16 
17     public Integer getId() {
18         return id;
19     }
20 
21     public void setId(Integer id) {
22         this.id = id;
23     }
24 
25     public String getTitle() {
26         return title;
27     }
28 
29     public void setTitle(String title) {
30         this.title = title;
31     }
32 
33     public double getPrice() {
34         return price;
35     }
36 
37     public void setPrice(double price) {
38         this.price = price;
39     }
40 
41 }
View Code

ProductItem.hbm.xml

 1 <?xml version="1.0"?>
 2 <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
 3 "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
 4 <!-- Generated 2017-6-7 22:33:53 by Hibernate Tools 3.5.0.Final -->
 5 <hibernate-mapping>
 6     <class name="com.dx.hibernate06.n2n.ProductItem" table="PRODUCT_ITEM">
 7         <id name="id" type="java.lang.Integer">
 8             <column name="ID" />
 9             <generator class="native" />
10         </id>
11         <property name="title" type="java.lang.String">
12             <column name="TITLE" />
13         </property>
14         <property name="price" type="double">
15             <column name="PRICE" />
16         </property>
17     </class>
18 </hibernate-mapping>
View Code

测试类TestMain.java 

 1 package com.dx.hibernate06.n2n;
 2 
 3 import java.util.Date;
 4 import java.util.Set;
 5 
 6 import org.hibernate.Session;
 7 import org.hibernate.SessionFactory;
 8 import org.hibernate.Transaction;
 9 import org.hibernate.boot.Metadata;
10 import org.hibernate.boot.MetadataSources;
11 import org.hibernate.boot.model.naming.ImplicitNamingStrategyComponentPathImpl;
12 import org.hibernate.boot.registry.StandardServiceRegistry;
13 import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
14 import org.hibernate.metamodel.internal.MapMember;
15 import org.junit.After;
16 import org.junit.Before;
17 import org.junit.Test;
18 
19 public class TestMain {
20     private SessionFactory sessionFactory = null;
21     private Session session = null;
22     private Transaction transaction = null;
23 
24     @Before
25     public void init() {
26         StandardServiceRegistry standardRegistry = new StandardServiceRegistryBuilder().configure().build();
27         Metadata metadata = new MetadataSources(standardRegistry).getMetadataBuilder().applyImplicitNamingStrategy(ImplicitNamingStrategyComponentPathImpl.INSTANCE).build();
28 
29         sessionFactory = metadata.getSessionFactoryBuilder().build();
30         session = sessionFactory.getCurrentSession();
31         transaction = session.beginTransaction();
32     }
33 
34     @After
35     public void destory() {
36         transaction.commit();
37         session.close();
38         sessionFactory.close();
39     }
40 }
View Code

 测试代码:

添加测试函数1:

 1     @Test
 2     public void testInsert() {
 3         ProductCategory category1 = new ProductCategory();
 4         category1.setName("category1");
 5         category1.setDetail("Detail");
 6 
 7         ProductCategory category2 = new ProductCategory();
 8         category2.setName("category2");
 9         category2.setDetail("Detail");
10 
11         ProductItem item1 = new ProductItem();
12         item1.setTitle("item1");
13         item1.setPrice(110.00);
14 
15         ProductItem item2 = new ProductItem();
16         item2.setTitle("item2");
17         item2.setPrice(110.00);
18 
19         category1.getProductItems().add(item1);
20         category1.getProductItems().add(item2);
21 
22         category2.getProductItems().add(item1);
23         category2.getProductItems().add(item2);
24 
25         session.save(category1);
26         session.save(category2);
27 
28         session.save(item1);
29         session.save(item2);
30     }

控制台打印sql

 1 Hibernate: 
 2     
 3     create table PRODUCT_CATEGORY (
 4        ID integer not null auto_increment,
 5         NAME varchar(255),
 6         DETAIL varchar(255),
 7         primary key (ID)
 8     ) engine=InnoDB
 9 Hibernate: 
10     
11     create table PRODUCT_CATEGORY_ITEM (
12        CATEGORY_ID integer not null,
13         ITEM_ID integer not null,
14         primary key (CATEGORY_ID, ITEM_ID)
15     ) engine=InnoDB
16 Hibernate: 
17     
18     create table PRODUCT_ITEM (
19        ID integer not null auto_increment,
20         TITLE varchar(255),
21         PRICE double precision,
22         primary key (ID)
23     ) engine=InnoDB
24 Hibernate: 
25     
26     alter table PRODUCT_CATEGORY_ITEM 
27        add constraint FKgqq9f2yg5b52m390yk15c8u28 
28        foreign key (ITEM_ID) 
29        references PRODUCT_ITEM (ID)
30 Hibernate: 
31     
32     alter table PRODUCT_CATEGORY_ITEM 
33        add constraint FKtajc52s55t4fk8864s63hsuv2 
34        foreign key (CATEGORY_ID) 
35        references PRODUCT_CATEGORY (ID)
View Code

查询数据库结果信息:

添加测试函数2:

1     @Test
2     public void testSelect() {
3         ProductCategory category = (ProductCategory) session.get(ProductCategory.class, 1);
4         System.out.println(category.getName());
5 
6         System.out.println(category.getProductItems().size());
7     }

后台执行sql及结果:

 1 Hibernate: 
 2     select
 3         productcat0_.ID as ID1_0_0_,
 4         productcat0_.NAME as NAME2_0_0_,
 5         productcat0_.DETAIL as DETAIL3_0_0_ 
 6     from
 7         PRODUCT_CATEGORY productcat0_ 
 8     where
 9         productcat0_.ID=?
10 category1
11 Hibernate: 
12     select
13         productite0_.CATEGORY_ID as CATEGORY1_1_0_,
14         productite0_.ITEM_ID as ITEM_ID2_1_0_,
15         productite1_.ID as ID1_2_1_,
16         productite1_.TITLE as TITLE2_2_1_,
17         productite1_.PRICE as PRICE3_2_1_ 
18     from
19         PRODUCT_CATEGORY_ITEM productite0_ 
20     inner join
21         PRODUCT_ITEM productite1_ 
22             on productite0_.ITEM_ID=productite1_.ID 
23     where
24         productite0_.CATEGORY_ID=?
25 2
  • 双向多对多:

 实现双向多对多,需要再ProductItem的另一端也定义Set属性:Set<ProductCategory> productCategories。还需要在ProductItem.hbm.xml中添加set节点,节点属性配置与ProductCategory.hbm.xml中set节点配置对调。

修改ProductItem.java(在类中添加属性:Set<ProductCategory> productCategories):

 1 package com.dx.hibernate06.n2n;
 2 
 3 import java.util.HashSet;
 4 import java.util.Set;
 5 
 6 public class ProductItem {
 7     private Integer id;
 8     private String title;
 9     private double price;
10     private Set<ProductCategory> productCategories = new HashSet<>();
11 
12     public ProductItem() {
13     }
14 
15     public ProductItem(String title, double price) {
16         super();
17         this.title = title;
18         this.price = price;
19     }
20 
21     public Integer getId() {
22         return id;
23     }
24 
25     public void setId(Integer id) {
26         this.id = id;
27     }
28 
29     public String getTitle() {
30         return title;
31     }
32 
33     public void setTitle(String title) {
34         this.title = title;
35     }
36 
37     public double getPrice() {
38         return price;
39     }
40 
41     public void setPrice(double price) {
42         this.price = price;
43     }
44 
45     public Set<ProductCategory> getProductCategories() {
46         return productCategories;
47     }
48 
49     public void setProductCategories(Set<ProductCategory> productCategories) {
50         this.productCategories = productCategories;
51     }
52 
53 }
View Code

修改ProductItem.hbm.xml配置文件(添加set节点,并在ProductItem.hbm.xml或者ProductCategory.hbm.xml的set节点中添加属性inverse="true"):

 1 <?xml version="1.0"?>
 2 <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
 3 "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
 4 <!-- Generated 2017-6-7 22:33:53 by Hibernate Tools 3.5.0.Final -->
 5 <hibernate-mapping>
 6     <class name="com.dx.hibernate06.n2n.ProductItem" table="PRODUCT_ITEM">
 7         <id name="id" type="java.lang.Integer">
 8             <column name="ID" />
 9             <generator class="native" />
10         </id>
11         <property name="title" type="java.lang.String">
12             <column name="TITLE" />
13         </property>
14         <property name="price" type="double">
15             <column name="PRICE" />
16         </property>
17 
18         <set name="productCategories" table="PRODUCT_CATEGORY_ITEM" inverse="true">
19             <key>
20                 <column name="ITEM_ID" />
21             </key>
22             <many-to-many class="com.dx.hibernate06.n2n.ProductCategory" column="CATEGORY_ID"></many-to-many>
23         </set>
24     </class>
25 </hibernate-mapping>

删除数据中的表,之后添加测试函数。

mysql> drop table PRODUCT_CATEGORY_ITEM;
Query OK, 0 rows affected (0.02 sec)

mysql> drop table PRODUCT_CATEGORY;
Query OK, 0 rows affected (0.02 sec)

mysql> drop table PRODUCT_ITEM;
Query OK, 0 rows affected (0.01 sec)

mysql> show tables;
+------------------------+
| Tables_in_hibernate_01 |
+------------------------+
| customer               |
| deparments             |
| managers               |
| member                 |
| memberdetail           |
| news                   |
| orders                 |
+------------------------+
7 rows in set (0.00 sec)

mysql>

 测试代码: 

添加测试函数1:

 1     @Test
 2     public void testInsert() {
 3         ProductCategory category1 = new ProductCategory();
 4         category1.setName("category1");
 5         category1.setDetail("Detail");
 6 
 7         ProductCategory category2 = new ProductCategory();
 8         category2.setName("category2");
 9         category2.setDetail("Detail");
10 
11         ProductItem item1 = new ProductItem();
12         item1.setTitle("item1");
13         item1.setPrice(110.00);
14 
15         ProductItem item2 = new ProductItem();
16         item2.setTitle("item2");
17         item2.setPrice(110.00);
18 
19         category1.getProductItems().add(item1);
20         category1.getProductItems().add(item2);
21         category2.getProductItems().add(item1);
22         category2.getProductItems().add(item2);
23 
24         item1.getProductCategories().add(category1);
25         item1.getProductCategories().add(category2);
26         item2.getProductCategories().add(category1);
27         item2.getProductCategories().add(category2);
28         
29         session.save(category1);
30         session.save(category2);
31 
32         session.save(item1);
33         session.save(item2);
34     }

测试执行sql:

 1 Hibernate: 
 2     
 3     create table PRODUCT_CATEGORY (
 4        ID integer not null auto_increment,
 5         NAME varchar(255),
 6         DETAIL varchar(255),
 7         primary key (ID)
 8     ) engine=InnoDB
 9 Hibernate: 
10     
11     create table PRODUCT_CATEGORY_ITEM (
12        CATEGORY_ID integer not null,
13         ITEM_ID integer not null,
14         primary key (CATEGORY_ID, ITEM_ID)
15     ) engine=InnoDB
16 Hibernate: 
17     
18     create table PRODUCT_ITEM (
19        ID integer not null auto_increment,
20         TITLE varchar(255),
21         PRICE double precision,
22         primary key (ID)
23     ) engine=InnoDB
24 Hibernate: 
25     
26     alter table PRODUCT_CATEGORY_ITEM 
27        add constraint FKgqq9f2yg5b52m390yk15c8u28 
28        foreign key (ITEM_ID) 
29        references PRODUCT_ITEM (ID)
30 Hibernate: 
31     
32     alter table PRODUCT_CATEGORY_ITEM 
33        add constraint FKtajc52s55t4fk8864s63hsuv2 
34        foreign key (CATEGORY_ID) 
35        references PRODUCT_CATEGORY (ID)
36 Hibernate: 
37     insert 
38     into
39         PRODUCT_CATEGORY
40         (NAME, DETAIL) 
41     values
42         (?, ?)
43 Hibernate: 
44     insert 
45     into
46         PRODUCT_CATEGORY
47         (NAME, DETAIL) 
48     values
49         (?, ?)
50 Hibernate: 
51     insert 
52     into
53         PRODUCT_ITEM
54         (TITLE, PRICE) 
55     values
56         (?, ?)
57 Hibernate: 
58     insert 
59     into
60         PRODUCT_ITEM
61         (TITLE, PRICE) 
62     values
63         (?, ?)
64 Hibernate: 
65     insert 
66     into
67         PRODUCT_CATEGORY_ITEM
68         (CATEGORY_ID, ITEM_ID) 
69     values
70         (?, ?)
71 Hibernate: 
72     insert 
73     into
74         PRODUCT_CATEGORY_ITEM
75         (CATEGORY_ID, ITEM_ID) 
76     values
77         (?, ?)
78 Hibernate: 
79     insert 
80     into
81         PRODUCT_CATEGORY_ITEM
82         (CATEGORY_ID, ITEM_ID) 
83     values
84         (?, ?)
85 Hibernate: 
86     insert 
87     into
88         PRODUCT_CATEGORY_ITEM
89         (CATEGORY_ID, ITEM_ID) 
90     values
91         (?, ?)
View Code

在数据中执行查询:

原文地址:https://www.cnblogs.com/yy3b2007com/p/6959532.html