• 背景:

  在实际开发中我们会遇到表的多对多关联,比如:一篇博客文章,它可以同时属于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. IntelliJ Idea常用的快捷键

    以下是IntelliJ Idea2017版的,基本上不会有什么变化 IntelliJ Idea这个编译器现在非常流行,他强大的快捷键非常好用,相比于eclipse,IntelliJ Idea界面也比e ...

  2. linux性能调试之iostat

    iostat用来监控调试linux系统的IO性能. 一般用法: iostat -xdct time_interval count [disk] -x:显示扩展统计项,如果不使用-x参数只会打印基本统计 ...

  3. Android短信验证码倒计时

    有两种实现方法 1.第一种方式:Timer /** * Description:自定义Timer * <p> * Created by Mjj on 2016/12/4. */ publi ...

  4. 【Django】 rest-framework和RestfulAPI的设计

    [rest-framework] 这是一个基于django才能发挥作用的组件,专门用于构造API的. 说到API,之前在其他项目中我也做过一些小API,不过那些都是玩票性质,结构十分简单而且要求的设计 ...

  5. Java中的序列化与反序列化

    序列化定义 将对象转换为字节流保存起来,并在以后还原这个对象,这种机制叫做对象序列化. 将一个对象保存到永久存储设备上称为持久化. 一个对象要想能够实现序列化,必须实现java.io.Serializ ...

  6. Idea  调试代码

    ---恢复内容开始--- set DEBUG_PORT=8787 set JAVA_DEBUG=-Xdebug -Xnoagent -Xrunjdwp:transport=dt_socket,addr ...

  7. [Java] JDK 环境配置(图文)

    Windows10 上的安装配置 1.前往 JDK 官网下载对应 jdk 版本安装包: http://www.oracle.com/technetwork/java/javase/downloads/ ...

  8. IDEA的快捷键的使用

    1.配置Intellij Idea的配置文件从默认c盘转移到其他盘符 找到Intellij idea的安装文件,在bin目录下找到idea.properties配置文件,如下把Idea的配置文件夹和I ...

  9. 基于Multiple treatment的营销评估算法

    营销是发现或挖掘准消费者和众多商家需求,通过对自身商品和服务的优化和定制,进而推广.传播和销售产品,实现最大化利益的过程.例如,银行可通过免息卡或降价对处在分期意愿边缘的用户进行营销,促使其分期进而提 ...

  10. 在Winform混合式框架中整合外部API接口的调用

    在我们常规的业务处理中,一般内部处理的接口多数都是以数据库相关的,基于混合式开发的Winform开发框架,虽然在客户端调用的时候,一般选择也是基于Web API的调用,不过后端我们可能不仅仅是针对我们 ...