• 背景:

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

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

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

  • 单向多对多:

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

 <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.connection.password">123456</property>
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hibernate.connection.url">jdbc:mysql://localhost/hibernate_01</property> <!-- <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
<property name="hibernate.dialect">org.hibernate.dialect.MySQLInnoDBDialect</property> -->
<property name="hibernate.dialect">org.hibernate.dialect.MySQL5InnoDBDialect</property> <property name="hibernate.show_sql">true</property> <property name="hibernate.format_sql">true</property> <property name="hibernate.hbm2ddl.auto">update</property> <property name="hibernate.current_session_context_class">thread</property> <property name="hibernate.c3p0.max_size">500</property>
<property name="hibernate.c3p0.min_size">20</property>
<property name="hibernate.c3p0.max_statements">10</property>
<property name="hibernate.c3p0.timeout">2000</property>
<property name="hibernate.c3p0.idle_test_period">2000</property>
<property name="hibernate.c3p0.acquire_increment">10</property> <mapping resource="com/dx/hibernate06/n2n/ProductCategory.hbm.xml" />
<mapping resource="com/dx/hibernate06/n2n/ProductItem.hbm.xml" /> </session-factory>
</hibernate-configuration>

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

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

 package com.dx.hibernate06.n2n;

 import java.util.HashSet;
import java.util.Set; public class ProductCategory {
private Integer id;
private String name;
private String detail;
private Set<ProductItem> productItems = new HashSet<>(); public ProductCategory() { } public ProductCategory(String name, String detail) {
super();
this.name = name;
this.detail = detail;
} public Integer getId() {
return id;
} public void setId(Integer id) {
this.id = id;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public String getDetail() {
return detail;
} public void setDetail(String detail) {
this.detail = detail;
} public Set<ProductItem> getProductItems() {
return productItems;
} public void setProductItems(Set<ProductItem> productItems) {
this.productItems = productItems;
} }

ProductCategory.hbm.xml

 <?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- Generated 2017-6-7 22:33:53 by Hibernate Tools 3.5.0.Final -->
<hibernate-mapping package="com.dx.hibernate06.n2n">
<class name="ProductCategory" table="PRODUCT_CATEGORY">
<id name="id" type="java.lang.Integer">
<column name="ID" />
<generator class="native" />
</id>
<property name="name" type="java.lang.String">
<column name="NAME" />
</property>
<property name="detail" type="java.lang.String">
<column name="DETAIL" />
</property> <set name="productItems" table="PRODUCT_CATEGORY_ITEM">
<key>
<column name="CATEGORY_ID" />
</key>
<many-to-many class="ProductItem" column="ITEM_ID"></many-to-many>
</set>
</class>
</hibernate-mapping>

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

ProductItem.java

 package com.dx.hibernate06.n2n;

 public class ProductItem {
private Integer id;
private String title;
private double price; public ProductItem() {
} public ProductItem(String title, double price) {
super();
this.title = title;
this.price = price;
} public Integer getId() {
return id;
} public void setId(Integer id) {
this.id = id;
} public String getTitle() {
return title;
} public void setTitle(String title) {
this.title = title;
} public double getPrice() {
return price;
} public void setPrice(double price) {
this.price = price;
} }

ProductItem.hbm.xml

 <?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- Generated 2017-6-7 22:33:53 by Hibernate Tools 3.5.0.Final -->
<hibernate-mapping>
<class name="com.dx.hibernate06.n2n.ProductItem" table="PRODUCT_ITEM">
<id name="id" type="java.lang.Integer">
<column name="ID" />
<generator class="native" />
</id>
<property name="title" type="java.lang.String">
<column name="TITLE" />
</property>
<property name="price" type="double">
<column name="PRICE" />
</property>
</class>
</hibernate-mapping>

测试类TestMain.java

 package com.dx.hibernate06.n2n;

 import java.util.Date;
import java.util.Set; import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.boot.Metadata;
import org.hibernate.boot.MetadataSources;
import org.hibernate.boot.model.naming.ImplicitNamingStrategyComponentPathImpl;
import org.hibernate.boot.registry.StandardServiceRegistry;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.metamodel.internal.MapMember;
import org.junit.After;
import org.junit.Before;
import org.junit.Test; public class TestMain {
private SessionFactory sessionFactory = null;
private Session session = null;
private Transaction transaction = null; @Before
public void init() {
StandardServiceRegistry standardRegistry = new StandardServiceRegistryBuilder().configure().build();
Metadata metadata = new MetadataSources(standardRegistry).getMetadataBuilder().applyImplicitNamingStrategy(ImplicitNamingStrategyComponentPathImpl.INSTANCE).build(); sessionFactory = metadata.getSessionFactoryBuilder().build();
session = sessionFactory.getCurrentSession();
transaction = session.beginTransaction();
} @After
public void destory() {
transaction.commit();
session.close();
sessionFactory.close();
}
}

测试代码:

添加测试函数1:

     @Test
public void testInsert() {
ProductCategory category1 = new ProductCategory();
category1.setName("category1");
category1.setDetail("Detail"); ProductCategory category2 = new ProductCategory();
category2.setName("category2");
category2.setDetail("Detail"); ProductItem item1 = new ProductItem();
item1.setTitle("item1");
item1.setPrice(110.00); ProductItem item2 = new ProductItem();
item2.setTitle("item2");
item2.setPrice(110.00); category1.getProductItems().add(item1);
category1.getProductItems().add(item2); category2.getProductItems().add(item1);
category2.getProductItems().add(item2); session.save(category1);
session.save(category2); session.save(item1);
session.save(item2);
}

控制台打印sql

 Hibernate: 

     create table PRODUCT_CATEGORY (
ID integer not null auto_increment,
NAME varchar(255),
DETAIL varchar(255),
primary key (ID)
) engine=InnoDB
Hibernate: create table PRODUCT_CATEGORY_ITEM (
CATEGORY_ID integer not null,
ITEM_ID integer not null,
primary key (CATEGORY_ID, ITEM_ID)
) engine=InnoDB
Hibernate: create table PRODUCT_ITEM (
ID integer not null auto_increment,
TITLE varchar(255),
PRICE double precision,
primary key (ID)
) engine=InnoDB
Hibernate: alter table PRODUCT_CATEGORY_ITEM
add constraint FKgqq9f2yg5b52m390yk15c8u28
foreign key (ITEM_ID)
references PRODUCT_ITEM (ID)
Hibernate: alter table PRODUCT_CATEGORY_ITEM
add constraint FKtajc52s55t4fk8864s63hsuv2
foreign key (CATEGORY_ID)
references PRODUCT_CATEGORY (ID)

查询数据库结果信息:

添加测试函数2:

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

后台执行sql及结果:

 Hibernate:
select
productcat0_.ID as ID1_0_0_,
productcat0_.NAME as NAME2_0_0_,
productcat0_.DETAIL as DETAIL3_0_0_
from
PRODUCT_CATEGORY productcat0_
where
productcat0_.ID=?
category1
Hibernate:
select
productite0_.CATEGORY_ID as CATEGORY1_1_0_,
productite0_.ITEM_ID as ITEM_ID2_1_0_,
productite1_.ID as ID1_2_1_,
productite1_.TITLE as TITLE2_2_1_,
productite1_.PRICE as PRICE3_2_1_
from
PRODUCT_CATEGORY_ITEM productite0_
inner join
PRODUCT_ITEM productite1_
on productite0_.ITEM_ID=productite1_.ID
where
productite0_.CATEGORY_ID=?
  • 双向多对多:

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

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

 package com.dx.hibernate06.n2n;

 import java.util.HashSet;
import java.util.Set; public class ProductItem {
private Integer id;
private String title;
private double price;
private Set<ProductCategory> productCategories = new HashSet<>(); public ProductItem() {
} public ProductItem(String title, double price) {
super();
this.title = title;
this.price = price;
} public Integer getId() {
return id;
} public void setId(Integer id) {
this.id = id;
} public String getTitle() {
return title;
} public void setTitle(String title) {
this.title = title;
} public double getPrice() {
return price;
} public void setPrice(double price) {
this.price = price;
} public Set<ProductCategory> getProductCategories() {
return productCategories;
} public void setProductCategories(Set<ProductCategory> productCategories) {
this.productCategories = productCategories;
} }

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

 <?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- Generated 2017-6-7 22:33:53 by Hibernate Tools 3.5.0.Final -->
<hibernate-mapping>
<class name="com.dx.hibernate06.n2n.ProductItem" table="PRODUCT_ITEM">
<id name="id" type="java.lang.Integer">
<column name="ID" />
<generator class="native" />
</id>
<property name="title" type="java.lang.String">
<column name="TITLE" />
</property>
<property name="price" type="double">
<column name="PRICE" />
</property> <set name="productCategories" table="PRODUCT_CATEGORY_ITEM" inverse="true">
<key>
<column name="ITEM_ID" />
</key>
<many-to-many class="com.dx.hibernate06.n2n.ProductCategory" column="CATEGORY_ID"></many-to-many>
</set>
</class>
</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:

     @Test
public void testInsert() {
ProductCategory category1 = new ProductCategory();
category1.setName("category1");
category1.setDetail("Detail"); ProductCategory category2 = new ProductCategory();
category2.setName("category2");
category2.setDetail("Detail"); ProductItem item1 = new ProductItem();
item1.setTitle("item1");
item1.setPrice(110.00); ProductItem item2 = new ProductItem();
item2.setTitle("item2");
item2.setPrice(110.00); category1.getProductItems().add(item1);
category1.getProductItems().add(item2);
category2.getProductItems().add(item1);
category2.getProductItems().add(item2); item1.getProductCategories().add(category1);
item1.getProductCategories().add(category2);
item2.getProductCategories().add(category1);
item2.getProductCategories().add(category2); session.save(category1);
session.save(category2); session.save(item1);
session.save(item2);
}

测试执行sql:

 Hibernate: 

     create table PRODUCT_CATEGORY (
ID integer not null auto_increment,
NAME varchar(255),
DETAIL varchar(255),
primary key (ID)
) engine=InnoDB
Hibernate: create table PRODUCT_CATEGORY_ITEM (
CATEGORY_ID integer not null,
ITEM_ID integer not null,
primary key (CATEGORY_ID, ITEM_ID)
) engine=InnoDB
Hibernate: create table PRODUCT_ITEM (
ID integer not null auto_increment,
TITLE varchar(255),
PRICE double precision,
primary key (ID)
) engine=InnoDB
Hibernate: alter table PRODUCT_CATEGORY_ITEM
add constraint FKgqq9f2yg5b52m390yk15c8u28
foreign key (ITEM_ID)
references PRODUCT_ITEM (ID)
Hibernate: alter table PRODUCT_CATEGORY_ITEM
add constraint FKtajc52s55t4fk8864s63hsuv2
foreign key (CATEGORY_ID)
references PRODUCT_CATEGORY (ID)
Hibernate:
insert
into
PRODUCT_CATEGORY
(NAME, DETAIL)
values
(?, ?)
Hibernate:
insert
into
PRODUCT_CATEGORY
(NAME, DETAIL)
values
(?, ?)
Hibernate:
insert
into
PRODUCT_ITEM
(TITLE, PRICE)
values
(?, ?)
Hibernate:
insert
into
PRODUCT_ITEM
(TITLE, PRICE)
values
(?, ?)
Hibernate:
insert
into
PRODUCT_CATEGORY_ITEM
(CATEGORY_ID, ITEM_ID)
values
(?, ?)
Hibernate:
insert
into
PRODUCT_CATEGORY_ITEM
(CATEGORY_ID, ITEM_ID)
values
(?, ?)
Hibernate:
insert
into
PRODUCT_CATEGORY_ITEM
(CATEGORY_ID, ITEM_ID)
values
(?, ?)
Hibernate:
insert
into
PRODUCT_CATEGORY_ITEM
(CATEGORY_ID, ITEM_ID)
values
(?, ?)

在数据中执行查询:

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

  1. Hibernate(十四)抓取策略

    抓取策略: 抓取策略是当应用程序需要在(Hibernate实体对象图的)关联关系间进行导航的时候,Hibernate如何获取关联对象的策略.Hibernate的抓取策略是Hibernate提升性能的一 ...

  2. hibernate(十)双向关联关系的CRUD

    本文链接:http://www.orlion.ml/28/ 一.保存 1. 假设一个group有多个user,一个user只属于一个group,当保存user对象到数据库中时可以 User u = n ...

  3. 在Hibernate单向一对多关联关系中的org.hibernate.StaleStateException 异常。

    具体异常如下: Caused by: org.hibernate.StaleStateException: Batch update returned unexpected row count fro ...

  4. Hibernate(十)__缓存机制

    为什么需要缓存? 缓存的作用主要用来提高性能,可以简单的理解成一个Map: 使 用缓存涉及到三个操作:把数据放入缓存.从缓存中获取数据. 删除缓存中的无效数据. 从上图看出: 当我们去查询对象的时候, ...

  5. Hibernate 映射多对多关联关系

    映射多对多,需要建立一张中间表 一共三张表,一个是 Category,一个是 Item,还有一个是 Categories_Items Categories_Items 作为中间表,其包含两个列,分别对 ...

  6. Hibernate(十五)注解

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

  7. Hibernate(十四)缓存

    一.什么是缓存 缓存是介于应用程序和永久必数据存储源之间,目的是为了降低应用程序直接读写永久必数据存储源的频率,从而提高运行性能 缓存通常是在内存中的如: Office中的Word.excel Hib ...

  8. Hibernate(十二)Criteria查询

    一.简述 Criteria是一种比hql更面向对象的查询方式.Criteria 可使用 Criterion 和 Projection 设置查询条件.可以设置 FetchMode(联合查询抓取的模式 ) ...

  9. Hibernate(十)HQL查询二

    一.数据库的emp名和dept表 建立持久化类和配置文件,可以用MyEclipse直接生成 持久化类 package entity; import java.util.Date; public cla ...

  10. Hibernate中一对多关联关系中的级联属性

    如果想通过级联属性删除一端的数据和多端的数据要使用 void org.hibernate.Session.delete(Object arg0) 方法. getSession().delete(tea ...

随机推荐

  1. 剑指Offer-删除链表中重复的结点

    package LinkedList; /** * 删除链表中重复的结点 * 在一个排序的链表中,存在重复的结点,请删除该链表中重复的结点,重复的结点不保留,返回链表头指针. * 例如,链表1-> ...

  2. 一篇关于Maven项目的jar包Shell启动脚本

    使用Maven作为项目jar包依赖的管理,常常会遇到命令行启动,笔者也是哥菜鸟,在做微服务,以及服务器端开发的过程中,常常会遇到项目的启动需要使用main方法,笔者潜心的研究了很多博客,发现大多写的都 ...

  3. 多进程浏览器、多线程页面渲染与js的单线程

    线程与进程 说到单线程,就得从操作系统进程开始说起.在早期的操作系统中并没有线程的概念,进程是能拥有资源和独立运行的最小单位,也是程序执行的最小单位.任务调度采用的是时间片轮转的抢占式调度方式,而进程 ...

  4. execCommand的复制

    <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title> ...

  5. Java集合:TreeMap源码剖析

    一.概念 TreeMap是基于红黑树结构实现的一种Map,要分析TreeMap的实现首先就要对红黑树有所了解. 要了解什么是红黑树,就要了解它的存在主要是为了解决什么问题,对比其他数据结构比如数组,链 ...

  6. [poj3984]迷宫问题_bfs

    迷宫问题 题目大意:给你一个5*5的矩阵,求左上角到左下角的最短路径. 注释:0或1的矩阵,1表示不能走,0表示能走,保证有唯一最短路径. 想法:bfs爆搜练习题.通过其实点,定义方向数组,然后进行b ...

  7. aws中的路由表

    参考官方文档: 由表中包含一系列被称为路由的规则,可用于判断网络流量的导向目的地. 在您的 VPC 中的每个子网必须与一个路由表关联:路由表控制子网的路由.一个子网一次只能与一个路由表关联,但您可以将 ...

  8. MobileNet_v2

    研究动机: 神经网络彻底改变了机器智能的许多领域,实现了超人的准确性.然而,提高准确性的驱动力往往需要付出代价:现代先进网络需要高度计算资源,超出许多移动和嵌入式应用的能力. 主要贡献: 发明了一个新 ...

  9. C#中的函数式编程:递归与纯函数(二)

    在序言中,我们提到函数式编程的两大特征:无副作用.函数是第一公民.现在,我们先来深入第一个特征:无副作用. 无副作用是通过引用透明(Referential transparency)来定义的.如果一个 ...

  10. JAVA_SE基础——23.类的定义

    黑马程序员入学blog ... java 面向对象的语言 对象:真实存在的唯一的实物. 比如:我家的狗, 类: 实际就是对某种类型事物的共性属性与行为的抽取.  抽象的概念...   比如说:车   ...