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>

在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 }

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>

备注:在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 }

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>

测试类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 }

测试代码:

添加测试函数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)

查询数据库结果信息:

添加测试函数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 }

修改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         (?, ?)

在数据中执行查询:

时间: 2024-11-10 11:34:12

Hibernate(十):n-n关联关系的相关文章

hibernate映射-双向n-n关联关系

(学习记录,错误不足之处,请您耐心指正^_^) hibernate映射-双向n-n关联关系 一.代码示例: {类文件↓} Category.class package com.zit.hibernate.n2n.both; import java.util.HashSet; import java.util.Set; public class Category { private Integer id; private String name; private Set<Item> items

Hibernate(十四)抓取策略

抓取策略: 抓取策略是当应用程序需要在(Hibernate实体对象图的)关联关系间进行导航的时候,Hibernate如何获取关联对象的策略.Hibernate的抓取策略是Hibernate提升性能的一种手段,可以在获取关联对象的时候,对发送的语句进行优化,但是往往抓取策略需要和延迟加载一起使用来提升性能. 延迟加载的分类: 延迟加载(lazy load)是(也称为懒加载)Hibernate关联关系对象默认的加载方式,延迟加载机制是为了避免一些无谓的性能开销而提出来的,所谓延迟加载就是当在真正需要

hibernate双向一对多关联关系

双向的多对一(一对多)关联关系: 其实这种关联关系就是把单向的多对一和单向的一对多的关联关系的整合.     只是说明一点: 代码:   package qau.edu.ren; import java.util.Date; import org.hibernate.Session; import org.hibernate.Transaction; import org.hibernate.cfg.Configuration; public class Test { public static

Hibernate学习笔记之关联关系

??关联关系是面向对象分析.面向对象设计最重要的知识,Hibernate完全可以理解这种关联关系,如果映射得当,Hibernate的关联映射将可以大大简化持久层数据的访问.关联关系大致有如下两类: 单向关系:只需单向访问关联端. 双向关系:关联的两端可以互相访问 注:双向关系没有N-1,因为双向关系1-N和N-1是完全相同的. 注意:无论单向关系,还是双向关系,是针对面向对象中的类的调用,与底层数据库关系有所差异,不要搞混了. 专业名词通俗解释: 持久化操作:将数据CRUD(增加(Create)

(八)Hibernate的一对多关联关系

一.概述 例如,以客户(Customer)和订单(Order)为例,一个客户能有多个订单,一个订单只能有一个客户. 从Customer到Order是一对多关联,在java类中的面向对象设计应该一个Customer对象包含多个Order对象,因此应该定义一个集合,来包含所有的Order对象. 从Order到Customer是多对一关联,在java类中设计每个Order对象需要关联一个Customer对象,因此Order类中应该定义一个Cutomer类型的属性,来引用关联的customer对象. 但

Hibernate(十四)缓存

一.什么是缓存 缓存是介于应用程序和永久必数据存储源之间,目的是为了降低应用程序直接读写永久必数据存储源的频率,从而提高运行性能 缓存通常是在内存中的如: Office中的Word.excel Hibernater中的Session以及SessionFactory 二.对旬在JVM中的生命周期 new 语句创建JAVA对象时,JVM会为当前对象分配一个内存 只要当前对象被其它资源引用,就会一直存在内存中 如果当前对象不被其它资源引用,就结结束生命周期 一个对象被其它生命周期未结束的对象引用,则这

Hibernate(十二)Criteria查询

一.简述 Criteria是一种比hql更面向对象的查询方式.Criteria 可使用 Criterion 和 Projection 设置查询条件.可以设置 FetchMode(联合查询抓取的模式 ) ,设置排序方式,Criteria 还可以设置 FlushModel (冲刷 Session 的方式)和 LockMode (数据库锁模式). Criteria本身只是查询的容器.Criteria查询又称对象查询 Criteria查询采用面向对象的方式封装查询条件.由Hibernater自动生成SQ

Hibernate(十)HQL查询二

一.数据库的emp名和dept表 建立持久化类和配置文件,可以用MyEclipse直接生成 持久化类 package entity; import java.util.Date; public class Emp implements java.io.Serializable { // Fields private Short empno; private Dept dept; private String ename; private String job; private Short mgr

Hibernate(十五)注解

一.Hibernate注解 使用注解的方式来注释类和属性,从而完成对象和关系的映射 二.步骤 三.注解标签 四.查询

Hibernate(十)__缓存机制

为什么需要缓存? 缓存的作用主要用来提高性能,可以简单的理解成一个Map: 使 用缓存涉及到三个操作:把数据放入缓存.从缓存中获取数据. 删除缓存中的无效数据. 从上图看出: 当我们去查询对象的时候,首先到一级缓存去取数据,如果有,则不到数据库中取, 如果没有则到数据库中取,同时在一级缓存中放入对象. 一级缓存,Session级共享 save,update,saveOrUpdate,load,get,list,iterate,lock这些方法都会将对象放在一级缓存中, 一级缓存不能控制缓存的数量