• 背景:

  在实际开发中我们会遇到表的多对多关联,比如:一篇博客文章,它可以同时属于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. 深入理解Java虚拟机(第2版) 笔记目录

    本篇为读深入理解Java虚拟机(第2版)一书的笔记目录. Java 运行期数据区 Java 垃圾回收算法 Java 内存分配策略 Java 类文件结构 Java 加载.链接.初始化 Java 类加载器

  2. CentOS7安装Postgresql

    执行命令 Yum install postgresql-server Yum install postgresql-contrib 安装完成后,检查postgresql的服务状态 Systemctl ...

  3. vue技术解析六之生命周期函数

  4. iOS CocoaPods一些特别的用法 指定版本、版本介绍、忽略警告

    简介 介绍一些CocoaPods一些特别的用法 CocoaPods github地址 CocoaPods 官方地址 1. 指定第三方库版本 1. 固定版本 target 'MyApp' do use_ ...

  5. 设计模式 --> (16)观察者模式

    观察者模式 定义对象间的 一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新.它还有两个别名,依赖(Dependents),发布- 订阅(Publish-Sub ...

  6. (转)关于 awk 的 pattern(模式)

    本文转自chinaunix http://bbs.chinaunix.net/thread-4246512-1-1.html   作者reyleon 我们知道, awk程序由一系列 pattern 以 ...

  7. RESTFul API设计指南及使用说明

    RESTFul API设计指南及使用说明 一. 协议 API与用户的通信协议,使用HTTP协议. 二. 域名 应尽量将API部署在专用域名之下(http://api.example.com) 也可以将 ...

  8. 关于Redis数据库 ---- 基础篇

    Redis数据库也被称为数据结构数据库,因为存储基于key-value模式. 其中,value值可以为字符串(string),哈希(map),列表(list),集合(set)和有序集合(zset). ...

  9. 云计算之路-阿里云上-容器难容:容器服务故障以及自建 docker swarm 集群故障

    3月21日,由于使用阿里云服务器自建 docker swarm 集群的不稳定,我们将自建 docker swarm 集群上的所有应用切换阿里云容器服务 swarm 版(非swarm mode). 3月 ...

  10. C语言博客作业--字符数组

    一.PTA实验作业 题目1:统计一行文本的单词个数 1. 本题PTA提交列表 2. 设计思路 Begin 定义字符型变量ch,pre=' ': 定义整型变量count://用来记录单词个数 count ...