Hibernate(十):n-n关联关系
- 背景:
在实际开发中我们会遇到表的多对多关联,比如:一篇博客文章,它可以同时属于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关联关系的更多相关文章
- Hibernate(十四)抓取策略
抓取策略: 抓取策略是当应用程序需要在(Hibernate实体对象图的)关联关系间进行导航的时候,Hibernate如何获取关联对象的策略.Hibernate的抓取策略是Hibernate提升性能的一 ...
- hibernate(十)双向关联关系的CRUD
本文链接:http://www.orlion.ml/28/ 一.保存 1. 假设一个group有多个user,一个user只属于一个group,当保存user对象到数据库中时可以 User u = n ...
- 在Hibernate单向一对多关联关系中的org.hibernate.StaleStateException 异常。
具体异常如下: Caused by: org.hibernate.StaleStateException: Batch update returned unexpected row count fro ...
- Hibernate(十)__缓存机制
为什么需要缓存? 缓存的作用主要用来提高性能,可以简单的理解成一个Map: 使 用缓存涉及到三个操作:把数据放入缓存.从缓存中获取数据. 删除缓存中的无效数据. 从上图看出: 当我们去查询对象的时候, ...
- Hibernate 映射多对多关联关系
映射多对多,需要建立一张中间表 一共三张表,一个是 Category,一个是 Item,还有一个是 Categories_Items Categories_Items 作为中间表,其包含两个列,分别对 ...
- Hibernate(十五)注解
一.Hibernate注解 使用注解的方式来注释类和属性,从而完成对象和关系的映射 二.步骤 三.注解标签 四.查询
- Hibernate(十四)缓存
一.什么是缓存 缓存是介于应用程序和永久必数据存储源之间,目的是为了降低应用程序直接读写永久必数据存储源的频率,从而提高运行性能 缓存通常是在内存中的如: Office中的Word.excel Hib ...
- Hibernate(十二)Criteria查询
一.简述 Criteria是一种比hql更面向对象的查询方式.Criteria 可使用 Criterion 和 Projection 设置查询条件.可以设置 FetchMode(联合查询抓取的模式 ) ...
- Hibernate(十)HQL查询二
一.数据库的emp名和dept表 建立持久化类和配置文件,可以用MyEclipse直接生成 持久化类 package entity; import java.util.Date; public cla ...
- Hibernate中一对多关联关系中的级联属性
如果想通过级联属性删除一端的数据和多端的数据要使用 void org.hibernate.Session.delete(Object arg0) 方法. getSession().delete(tea ...
随机推荐
- Ambari Log Search
文章作者:luxianghao 文章来源:http://www.cnblogs.com/luxianghao/p/8630195.html 转载请注明,谢谢合作. 免责声明:文章内容仅代表个人观点, ...
- 剑指Offer-平衡二叉树
package Tree; /** * 平衡二叉树 * 输入一棵二叉树,判断该二叉树是否是平衡二叉树. * 平衡二叉树(Balanced Binary Tree)又被称为AVL树(有别于AVL算法), ...
- Java基础_Java概述
Java_概述 特点: 平台的移植性 开源 面向对象 多线程 安全性 工作方式: 先编译再解释执行. 先通过Javac命令将Java源代码编译成字节码文件(bytecode,类文件,.class,中间 ...
- 设置placeholder字体的颜色
::-webkit-input-placeholder { /* WebKit browsers */ color:#999; } :-moz-placeholder { /* Mozilla Fir ...
- python PIL模块学习
PIL PIL:Python Imaging Library.对于图像识别,大量的工作在于图像的处理,处理效果好,那么才能很好地识别,因此,良好的图像处理是识别的基础. PIL安装 安装推荐别人的吧, ...
- linux scp 命令
scp 命令 scp 命令 意思是 secure copy 即安全拷贝,可以把它看做是 cp 命令的高级版,可以跨主机拷贝. 经常用来在局域网内不同主机之间分享文件,或者在本机与远程主机中分享文件. ...
- 听翁恺老师mooc笔记(15)--文件的输入与输出
<>重定向 如果使用标准的printf输出,有一个比较简便的方法,可以将程序的结果写入一个文件.使用<和>符号,将程序运行结果重定向到文件中去,具体使用到的代码如下: ./te ...
- NetFPGA-1G-CML从零开始环境配置
NetFPGA-1G-CML从零开始环境配置 前言 偶得一块NetFPGA-1G-CML,跟着github对NetFPGA-1G-CML的入门指南,一步步把配置环境终于搭建起来,下面重新复现一下此过程 ...
- 6块300G SCSI RAID5,两块硬盘损坏的数据恢复总结
[用户单位]XXXX网站[数据恢复故障描述]DELL POWEREDGE 2850服务器,内置6块300G SCSI硬盘 ,组成RAID5,安装LINUX REDHAT 4操作系统,存储大量照片,文件 ...
- DELL EqualLogic PS存储硬盘故障数据恢复成功案例分享
DELL EqualLogic PS4000采用虚拟ISCSI SAN阵列,为远程或分支办公室.部门和中小企业存储部署带来企业级功能.智能化.自动化和可靠性.以简化的管理.快速的部署及合理的价格满足了 ...