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 ...
随机推荐
- Intel 移位指令的陷阱(转)
今天发现了一个Intel逻辑左移指令shl的一个bug. 逻辑左移的概念是对给定的目的操作数左移COUNT次,每次移位时最高位移入标志位CF中,最低位补零. 其中OPRD1为目的操作数, 可以是通 ...
- Mycat 分片规则详解--ASCII 取模范围分片
实现方式:该算法与取模范围算法类似,该算法支持数值.符号.字母取模.首先截取长度为 prefixLength 的子串,在对子串中每一个字符的 ASCII 码求和,然后对求和值进行取模运算(sum%pa ...
- kvm之六:配置kvm虚拟机通过VNC访问
1.网络安装的snale2没有添加VNC访问方式,配置如下 [root@kvm ~ ::]#virsh edit snale2 插入如下配置: <graphics type=' autoport ...
- (译文)学习ES6非常棒的特性-深入研究var, let and const
Var var firstVar; //firstVar被声明,它的默认值是undefined var secondVar = 2; //secondVar被声明,被赋值2 先看一个例子: var i ...
- Git 建立仓库及常用命令速查表
Git新建仓库两种模式: 一.项目在本地时,本地初始化仓库并提交至Coding.Net 新建一个空白目录并进入,执行如下流程 1.git init2.项目代码复制到当前目录3.git add *4.g ...
- Beta总结篇
45°炸 031502601 蔡鸿杰 031502604 陈甘霖 031502632 伍晨薇 一.项目预期进展及现实进展 项目预期计划 现实进展 Github使用 √ 日拍 (调用相机.相册) √ 足 ...
- C语言——第六周作业
题目 题目一:高速公路超速处罚 1.实验代码 #include <stdio.h> int main() { int speed,maxspeed; double x; scanf(&qu ...
- JAVA_SE基础——3.Java程序的开发流程
上一篇,写的是JAVA的环境变量的配置,今天我抽空写篇Java程序的开发流程,下面的教程是我结合书本和毕向东老师的视频写下的心的~ 在没有真正写Java程序前,首先需要了解Java程序的开发过程. S ...
- 一个诚实的孩纸选Python的原因
我之所以会选择python语言程序设计这门课,是因为我一开始预选选的选修课都没选上,然后在补选的时候,在别人选剩的课里面选择了python. 上了两节课之后,我发现python还挺有意思的,挺喜欢py ...
- js window
window对象: browser object mode :bom对象. bom提供了独立于内容而与浏览器窗口进行交互的对象. bom主要用于管理窗口与窗口之间的通讯,因此其核心对象是window ...