首页 > 代码库 > Hibernate(十):n-n关联关系

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     @Before25     public void init() {26         StandardServiceRegistry standardRegistry = new StandardServiceRegistryBuilder().configure().build();27         Metadata metadata = http://www.mamicode.com/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     @After35     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=InnoDB16 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=InnoDB24 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     @Test2     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 category111 Hibernate: 12     select13         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     from19         PRODUCT_CATEGORY_ITEM productite0_ 20     inner join21         PRODUCT_ITEM productite1_ 22             on productite0_.ITEM_ID=productite1_.ID 23     where24         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=InnoDB16 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=InnoDB24 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     into39         PRODUCT_CATEGORY40         (NAME, DETAIL) 41     values42         (?, ?)43 Hibernate: 44     insert 45     into46         PRODUCT_CATEGORY47         (NAME, DETAIL) 48     values49         (?, ?)50 Hibernate: 51     insert 52     into53         PRODUCT_ITEM54         (TITLE, PRICE) 55     values56         (?, ?)57 Hibernate: 58     insert 59     into60         PRODUCT_ITEM61         (TITLE, PRICE) 62     values63         (?, ?)64 Hibernate: 65     insert 66     into67         PRODUCT_CATEGORY_ITEM68         (CATEGORY_ID, ITEM_ID) 69     values70         (?, ?)71 Hibernate: 72     insert 73     into74         PRODUCT_CATEGORY_ITEM75         (CATEGORY_ID, ITEM_ID) 76     values77         (?, ?)78 Hibernate: 79     insert 80     into81         PRODUCT_CATEGORY_ITEM82         (CATEGORY_ID, ITEM_ID) 83     values84         (?, ?)85 Hibernate: 86     insert 87     into88         PRODUCT_CATEGORY_ITEM89         (CATEGORY_ID, ITEM_ID) 90     values91         (?, ?)
View Code

在数据中执行查询:

技术分享

 

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