///
Hibernate:
///
多对多关联是Hibernate中一种比较特殊的关联,它需要借助中间表来完成多对多信息的保存。多对多关联只有双向关联。
对于一个订单(Order)可以包含多种产品(Products),而对于每种产品可以存在于多个订单之中,是一个典型的多对多关系。
本次演示用到的两个POJO类如下:
public class Order
{
private Integer id;
private String name;
private String num;
private Set<Product> products = new HashSet<Product>();//
......
}
public class Product
{
private Integer id;
private String name;
private Set<Order> orders = new HashSet<Order>();//
......
}
它们对应的映射文件分别为:
Order.hbm.xml
<hibernate-mapping package="org.louis.domain">
<class name="Order" table="TEST_ORDER">
<id name="id" column="ID">
<generator class="native"></generator>
</id>
<property name="name" column="NAME"></property>
<property name="num" column="NUM"></property>
<set name="products" table="TEST_ORDER_PRODUCT" cascade="save-update" fetch="join">
<key column="ORDER_ID"></key>
<many-to-many class="Product" column="PRODUCT_ID"></many-to-many>
</set>
</class>
</hibernate-mapping>
Product.hbm.xml
<hibernate-mapping package="org.louis.domain">
<class name="Product" table="TEST_PRODUCT">
<id name="id" column="ID">
<generator class="native"></generator>
</id>
<property name="name" column="NAME"></property>
<set name="orders" table="TEST_ORDER_PRODUCT" cascade="save-update" fetch="join">
<key column="PRODUCT_ID"></key>
<many-to-many class="Order" column="ORDER_ID"></many-to-many>
</set>
</class>
</hibernate-mapping>
我们注意到,在两个文件中都有<set>节点,同时都指定了其table属性,这是两个对象的的中间表,在多对多关联中,
很多操作都是通过的中间表来完成的;<set>元素的子元素<key>指定了中间表中的外键,它对应于当前文件的对象的
主键,如Order.hbm.xml中,对应于Order的主键;<many-to-many>指定了关联的另一方和中间表的对应于另一方主键
的外键。
下面来做一些测试。
a、插入数据
public void insert()
{
Session session = HibernateSessionFactory.getSessionFactory().getCurrentSession();
session.beginTransaction();
Product p1 = new Product();
p1.setName("p1");
Product p2 = new Product();
p2.setName("p2");
Order order = (Order)session.load(Order.class, 3);
// order.getProducts().add(p1);
// order.getProducts().add(p2);
p1.getOrders().add(order);
p2.getOrders().add(order);
session.save(p1);
session.save(p2);
session.getTransaction().commit();
}
查看Hibernate在后台执行的SQL语句如下:
Hibernate:
select
order0_.ID as ID6_1_,
order0_.NAME as NAME6_1_,
order0_.NUM as NUM6_1_,
order0_.MEMBER_ID as MEMBER4_6_1_,
products1_.ORDER_ID as ORDER1_3_,
product2_.ID as PRODUCT2_3_,
product2_.ID as ID8_0_,
product2_.NAME as NAME8_0_
from
TEST_ORDER order0_
left outer join
TEST_ORDER_PRODUCT products1_
on order0_.ID=products1_.ORDER_ID
left outer join
TEST_PRODUCT product2_
on products1_.PRODUCT_ID=product2_.ID
where
order0_.ID=?
Hibernate:
insert
into
TEST_PRODUCT
(NAME)
values
(?)
Hibernate:
insert
into
TEST_PRODUCT
(NAME)
values
(?)
Hibernate:
insert
into
TEST_ORDER_PRODUCT
(PRODUCT_ID, ORDER_ID)
values
(?, ?)
Hibernate:
insert
into
TEST_ORDER_PRODUCT
(PRODUCT_ID, ORDER_ID)
values
(?, ?)
第一条是更加ID加载Order对象,同时将其关联对象也加载了。接着插入两个Product,然后用两条SQL语句向中间表里面插入反映关联关系的数据。
如果将Java代码修改为下面这样:
public void insert()
{
Session session = HibernateSessionFactory.getSessionFactory().getCurrentSession();
session.beginTransaction();
Product p1 = new Product();
p1.setName("p1");
Product p2 = new Product();
p2.setName("p2");
Order order = (Order)session.load(Order.class, 3);
order.getProducts().add(p1);
order.getProducts().add(p2);
session.save(order);
session.getTransaction().commit();
}
我们发现Hibernate执行的SQL和上面的一样,由此看来,在这种多对多情况下,无论让谁来维护关系都是可以的,因为默认
情况下inverse="false";
我们再来看当设置Product.hbm.xml中的<set>节点属性inverse="true", 这表示对于两个对象的关联关系的维护有Order来做。
我们使用下面的代码来测试一下:
public void insert()
{
Session session = HibernateSessionFactory.getSessionFactory().getCurrentSession();
session.beginTransaction();
Product p1 = new Product();
p1.setName("p1");
Product p2 = new Product();
p2.setName("p2");
Order order = (Order)session.load(Order.class, 3);
// order.getProducts().add(p1);
// order.getProducts().add(p2);
p1.getOrders().add(order);
p2.getOrders().add(order);
session.save(p1);
session.save(p2);
session.getTransaction().commit();
}
在这段代码中,明显可以看出关联关系的维护交给了Product来做了,这个Product.hbm.xml中配置的方式相矛盾,因此
必然会在保存数据的时候出现问题。运行这段代码,查看后台HIbernate使用的SQL语句为:
Hibernate:
select
order0_.ID as ID6_1_,
order0_.NAME as NAME6_1_,
order0_.NUM as NUM6_1_,
order0_.MEMBER_ID as MEMBER4_6_1_,
products1_.ORDER_ID as ORDER1_3_,
product2_.ID as PRODUCT2_3_,
product2_.ID as ID8_0_,
product2_.NAME as NAME8_0_
from
TEST_ORDER order0_
left outer join
TEST_ORDER_PRODUCT products1_
on order0_.ID=products1_.ORDER_ID
left outer join
TEST_PRODUCT product2_
on products1_.PRODUCT_ID=product2_.ID
where
order0_.ID=?
Hibernate:
insert
into
TEST_PRODUCT
(NAME)
values
(?)
Hibernate:
insert
into
TEST_PRODUCT
(NAME)
values
(?)
从这段SQL代码可以看出,只是进行了Product数据的插入,并没有对反映Order和Product关系的中间表进行数据
插入,看来配置文件中的设定由Order来维护关联关系起了一定的作用(为什么是一定的作用而不是完全的呢?这
是因为还没有进行必要的测试,只是在这里反映出Product已经不能维护关联关系了)。
下面我们将Java代码改动一下如下:
public void insert()
{
Session session = HibernateSessionFactory.getSessionFactory().getCurrentSession();
session.beginTransaction();
Product p1 = new Product();
p1.setName("p1");
Product p2 = new Product();
p2.setName("p2");
Order order = (Order)session.load(Order.class, 3);
order.getProducts().add(p1);
order.getProducts().add(p2);
session.save(order);
session.getTransaction().commit();
}
再次运行,查看后台SQL语句如下:
Hibernate:
select
order0_.ID as ID6_1_,
order0_.NAME as NAME6_1_,
order0_.NUM as NUM6_1_,
order0_.MEMBER_ID as MEMBER4_6_1_,
products1_.ORDER_ID as ORDER1_3_,
product2_.ID as PRODUCT2_3_,
product2_.ID as ID8_0_,
product2_.NAME as NAME8_0_
from
TEST_ORDER order0_
left outer join
TEST_ORDER_PRODUCT products1_
on order0_.ID=products1_.ORDER_ID
left outer join
TEST_PRODUCT product2_
on products1_.PRODUCT_ID=product2_.ID
where
order0_.ID=?
Hibernate:
insert
into
TEST_PRODUCT
(NAME)
values
(?)
Hibernate:
insert
into
TEST_PRODUCT
(NAME)
values
(?)
Hibernate:
insert
into
TEST_ORDER_PRODUCT
(ORDER_ID, PRODUCT_ID)
values
(?, ?)
Hibernate:
insert
into
TEST_ORDER_PRODUCT
(ORDER_ID, PRODUCT_ID)
values
(?, ?)
显然,和没有使用任何inverse="true"时的情况一摸一样,是正确的,也就是说现在是由Order来维护两个关联对象的关联关系的。
对于多对多关联来说,可以在任何一端来设置为主控方,也可都不设,那么两端都可以维护关联关系(并且,我们发现和设定一方
为主控方在性能上没有什么变化)。
如果两端都设定为inverse="true"的话呢?
我们来做个测试,将两个映射文件的<set>节点的inverse属性都设置为true。对于Order来说,是让Product作为主控方;对于
Product来说让Order作为主控方。
先用下面代码测试:
public void insert()
{
Session session = HibernateSessionFactory.getSessionFactory().getCurrentSession();
session.beginTransaction();
Product p1 = new Product();
p1.setName("p1");
Product p2 = new Product();
p2.setName("p2");
Order order = (Order)session.load(Order.class, 3);
// order.getProducts().add(p1);
// order.getProducts().add(p2);
p1.getOrders().add(order);
p2.getOrders().add(order);
session.save(p1);
session.save(p2);
session.getTransaction().commit();
}
查看后台SQL语句如下:
Hibernate:
select
order0_.ID as ID6_1_,
order0_.NAME as NAME6_1_,
order0_.NUM as NUM6_1_,
order0_.MEMBER_ID as MEMBER4_6_1_,
products1_.ORDER_ID as ORDER1_3_,
product2_.ID as PRODUCT2_3_,
product2_.ID as ID8_0_,
product2_.NAME as NAME8_0_
from
TEST_ORDER order0_
left outer join
TEST_ORDER_PRODUCT products1_
on order0_.ID=products1_.ORDER_ID
left outer join
TEST_PRODUCT product2_
on products1_.PRODUCT_ID=product2_.ID
where
order0_.ID=?
Hibernate:
insert
into
TEST_PRODUCT
(NAME)
values
(?)
Hibernate:
insert
into
TEST_PRODUCT
(NAME)
values
(?)
看来没有对中间表进行数据插入。
使用下面代码来测试:
public void insert()
{
Session session = HibernateSessionFactory.getSessionFactory().getCurrentSession();
session.beginTransaction();
Product p1 = new Product();
p1.setName("p1");
Product p2 = new Product();
p2.setName("p2");
Order order = (Order)session.load(Order.class, 3);
order.getProducts().add(p1);
order.getProducts().add(p2);
session.save(order);
session.getTransaction().commit();
}
查看后台的SQL语句如下:
Hibernate:
select
order0_.ID as ID6_1_,
order0_.NAME as NAME6_1_,
order0_.NUM as NUM6_1_,
order0_.MEMBER_ID as MEMBER4_6_1_,
products1_.ORDER_ID as ORDER1_3_,
product2_.ID as PRODUCT2_3_,
product2_.ID as ID8_0_,
product2_.NAME as NAME8_0_
from
TEST_ORDER order0_
left outer join
TEST_ORDER_PRODUCT products1_
on order0_.ID=products1_.ORDER_ID
left outer join
TEST_PRODUCT product2_
on products1_.PRODUCT_ID=product2_.ID
where
order0_.ID=?
Hibernate:
insert
into
TEST_PRODUCT
(NAME)
values
(?)
Hibernate:
insert
into
TEST_PRODUCT
(NAME)
values
(?)
比较两次的结果,发现一摸一样。看来如果两端都设置为主控方,是不能对中间表进行数据保存的。
b、数据加载
数据加载就不再演示了,也就是默认采用左外连接的方式加载数据,能够将Order和它的关联对象
Product都加载,当然是通过中间表;对于Product来说也是这样。
c、删除数据
删除数据也不再演示,无论删除Order还是Product,都是简单的删除自己,而不会删除关联的对象
,这是因为设定了cascade="save-update"
分享到:
相关推荐
hibernate笔记整理hibernate笔记整理hibernate笔记整理hibernate笔记整理
学习hibernate框架时,整理的笔记,对hibernate框架有全面的介绍
全方位学习hibernate必备,这是本人学习过程中整理的笔记。相信可以对你的hibernate学习有所帮助!
学习hibernate框架笔记整理和自己对hibernate认知,相互学习
韩顺平的hibernate笔记资料,详细记录讲课的内容和整理的图像资料
尚学堂hibernate学习笔记(原版整理),配合视频教程使用
Java Hibernate4天学习笔记整理可用于提交作业
hibernate课程笔记.doc,传智老师的用的笔记,个人也在整理过,对于初学者来说很实用。
个人整理的有关hibernate的一点点笔记
自己做的一个笔记,希望对你有用。一会我会上传源代码的。
马士兵hibernate学习笔记(文字整理版).
这是在培训机构培训完后整理的JDBC&Hibernate学习笔记,其中收集了自己遇到的问题。
达内Java 开发教学笔记整理合集: Unix 笔记 Core JAVA 笔记 OOAD思想 笔记 Oracle 笔记 JDBC 笔记 Hibernate 笔记 HTML&java script 笔记 Servlet 笔记 Jsp 笔记 Struts 1.2 笔记 Struts 2 笔记 Ajax 笔记 Spring ...
传智播客_hibernate李勇笔记是在学习李勇老师讲的hibernate3.2.5后整理的笔记
Hibernate精品笔记,诚心整理,必属精品
hibernate读书笔记,里面有一些实例和解说,是自己整理的,非常适合开发时做参考
hibernate学习笔记,个人整理的马士兵老师系列讲座的笔记,有些内容是补充的。
我自己在学习过程中做的电子笔记和一些要点的整理,希望发感兴趣的朋友下载,才一分,看在我辛辛苦苦整理的份上,不要嫌要下载分哦!