在hibernate中一对多关联时会经常用到inverse和cascade属性 ,inverse 有两个值 true ,false ;如果设置为true 则表示当前对象不负责将级联对象的状态变化同步到数据库 ;设置false则相反,其默认值为false;
cascade 有五个选项 分别是: all ,delete ,none,save-update,delete-orphan ;
all : 所有情况下均进行关联操作。
none:所有情况下均不进行关联操作。这是默认值。
save-update:在执行save/update/saveOrUpdate时进行关联操作。
delete:在执行delete时进行关联操作。
delete-orphan: 当save/update/saveOrUpdate时,相当于save-update ;当删除操作时,相当于delete ;
all的意思是save-update + delete
all-delete-orphan 的意思是当对象图中产生孤儿节点时,在数据库中删除该节点
all比较好理解,举个例子说一下all-delete-orphan:
Category(种类)与Item是一对多的关系,也就是说Category类中有个Set类型的变量items.
举个例子,现items中存两个Item, item1,item2,如果定义关系为all-delete-orphan
当items中删除掉一个item(比如用remove()方法删除item1),那么被删除的Item类实例
将变成孤儿节点,当执行category.update(),或session.flush()时
hibernate同步缓存和数据库,会把数据库中item1对应的记录删掉测试Hibernate中的三个属性:lazy,inverse,cascade
【测试环境】
一对多关系的两张表:boy、girl(一个男孩可以多个女朋友)
boy表结构
Field Type
------ -----------
name varchar(50) pk
age varchar(50)
girl表结构
Field Type
------ -----------
name varchar(50) pk
bf varchar(50) fk
【保存时:Inverse与cascade】
创建三个girl对象和一个boy对象,让这是三个girl都是boy的女朋友
---------创建对象的代码片段-----------
Boy boy = new Boy("tom","23", null);
Set girls = new HashSet();
Girl g[] = new Girl[]{
new Girl("Alice1", boy),
new Girl("Alice2", boy),
new Girl("Alice3", boy)};
girls.add(g[0]);
girls.add(g[1]);
girls.add(g[2]);
boy.setGirls(girls);
在Boy.hbm.xml中设置,然后对boy对象进行保存。
1.Inverse = true,不指定cascade
cascade的默认值为none, 当对boy进行保存操作时,girl什么都不做. 所以只保存了boy对象, 没有保存girl对象
2.Inverse = true,cascade=all
boy与girl对象,包扩外键都成功保存。
(生成3条SELECT语句和4条INSERT语句,一下简称SELECT 3, INSERT 4)
3.Inverse = false,不指定cascade
报错。因为boy为主控方,负责维护关系,所以在插入boy对象后,会尝试修改并不存在的girl对象。
4.Inverse = false,cascade=all
boy与girl对象,包扩外键都成功保存。
(SELECT 4, INSERT 4, UPDATE 3)
分析:除了4条INSERT语句之外,其他的6条语句是我们为了图方便付出的代价:3条SELECT语句用来判断girl对象是否在数据表中已经存在,3条UPDATE语句是为了维护外键关系
高效率的做法:在Boy.hbm.xml中设置Inverse=true,在Girl.hbm.xml中设置Inverse=false, cascade=all,然后保存三个girl对象
(SELECT 1, INSERT 4)
高效率的代价就是保存的时候比较麻烦
【删除时:Inverse与cascade】
希望通过删除boy,也将3个girl对象删除。程序中先查出boy对象,然后进行删除
-----------------------------------------
Boy boy = (Boy) s.get(Boy.class, "tom");
s.delete(boy);
-----------------------------------------
同样在Boy.hbm.xml中进行设置
1.Inverse = true
可以猜到结果是出错。原因:外键约束错误
2.Inverse = false
boy删除,girl表中外键变为null,没有删除记录 ;
(UPDATE 1, DELETE 1)
3.Inverse = false, cascade = all
全部删除 ;在删除有外键的从表时,先把从表外键置为null,然后删除主表记录,最后根据从表主键删除所有相关从表记录
(UPDATE 1, DELETE 4)
4.Inverse = true, cascade = all
全部删除
(DELETE 4)
Inverse是hibernate双向关系中的基本概念,当然对于多数实体,我们并不需要双向关联,更多的可能会选择单向关联,况且我们大多数人一般采用一对多关系,而一对多双向关联的另一端:多对一的inverse属性是不存在,其实 它默认就是inverse=false.从而防止了在一对多端胡乱设置inverse也不至于出错。但是inverse设置不当确实会带来很大的性能影响,这点是我们必须关注的。这篇文章已经详细分析了inverse设置不当带来的影响:http://www.hibernate.org/155.html
看了这篇文章,还是很有必要再写下一些总结的:
1)inverse中提及的side其实是指一个类或者表的概念,双向关联其实是指双方都可以取得对方的应用。
2)维护关系这个名词还是稍显模糊或者晦涩。我们一般说A类或者A表(这里的表的是指多对多的连接表)有责任维护关系,其实这里的意思是说,我在应用在更新,创建,删除(读就不用说了,双向引用正是为了方便读而出现)A类或者A表时,此时创建的SQL语句必须有责任保证关系的正确修改。
3)inverse=false的side(side其实是指inverse=false所位于的class元素)端有责任维护关系,而inverse=true端无须维护这些关系。
4)我们说inverse设立不当会导致性能低下,其实是说inverse设立不当,会产生多余重复的SQL语句甚至致使JDBC exception的throw。这是我们在建立实体类关系时必须需要关注的地方。一般来说,inverse=true是推荐使用,双向关联中双方都设置 inverse=false的话,必会导致双方都重复更新同一个关系。但是如果双方都设立inverse=true的话,双方都不维护关系的更新,这也是 不行的,好在一对多中的一端:many-to-one默认是inverse=false,避免了这种错误的产生。但是多对多就没有这个默认设置了,所以很多人经常在多对多的两端都使用inverse=true,结果导致连接表的数据根本没有记录,就是因为他们双分都没有责任维护关系。所以说,双向关联中最好的设置是一端为inverse=true,一端为inverse=false。一般inverse=false会放在多的一端,那么有人提问了, many-to-many两边都是多的,inverse到底放在哪儿?其实hibernate建立多对多关系也是将他们分离成两个一对多关系,中间连接一个连接表。所以通用存在一对多的关系,也可以这样说:一对多是多对多的基本组成部分。
看下面的多对多的定义大家更会清楚”多对多“与“一对多”的关系:其中我们注意<many-to-many />标签的特点就知道,它是定义了一个多对多关系,而不是<one-to-many/>。
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 2.0//EN"://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd">http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd">
<hibernate-mapping package="org.hibernate.auction">
<class name="TestA" table="TestA"
dynamic-update="true" dynamic-insert="true" > <id name="id" column="id" type="int" unsaved-value="any" >
<generator class="assigned">
</generator>
</id>
<property name="name" type="java.lang.String"
update="true" insert="true" column="name" />
<set name="testBs" table="TestA_TestB" inverse="false" cascade="all">
<key column="testA"/>
<many-to-many column="testB" class="TestB" />
</set>
</class>
<class name="TestB" table="TestB"
dynamic-update="true" dynamic-insert="true" >
<id name="id" column="id" type="int" unsaved-value="any" >
<generator class="assigned">
</generator>
</id>
<property name="name" type="java.lang.String" update="true"
insert="true" column="name" />
<set name="testAs" table="TestA_TestB" inverse="true" cascade="all">
<key column="testB"/>
<many-to-many column="testA" class="TestA" />
</set>
</class>
</hibernate-mapping>
在对多对中,因为一端维护关系另一端不维护关系的原因,我们必须注意避免在应用中用不维护关系的类建立关系,因为这样建立的关系是不会在数据库中存储的。基于上面的映射文件代码给出一个例子:
package org.hibernate.auction;
import java.util.*;
/**
* @author Administrator
*
* To change the template for this generated type comment go to
* Window>Preferences>Java>Code Generation>Code and Comments
*/
public class TestA {
int id;
String name;
Set testBs=new HashSet();
public TestA(){
}
public TestA(int id){
setId(id);
}
public int getId(){
return id;
}
public void setId(int id){
this.id=id;
}
public String getName(){
return name;
}
public void setName(String name){
this.name=name;
}
public Set getTestBs(){
return testBs;
}
public void setTestBs(Set s){
testBs=s;
}
public void addTestB(TestB tb){
testBs.add(tb);
}
public static void main(String[] args) {
}
}
public class TestB {
int id;
String name;
Set testAs=new HashSet();
public TestB(){
}
public TestB(int id){
setId(id);
}
public int getId(){
return id;
}
public void setId(int id){
this.id=id;
}
public String getName(){
return name;
}
public void setName(String name){
this.name=name;
}
public Set getTestAs(){
return testAs;
}
public void setTestAs(Set s){
testAs=s;
}
public void addTestA(TestA ta){
testAs.add(ta);
}
public static void main(String[] args) {
}
}
测试代码:
public void doTest() throws Exception{
TestA a1=new TestA(1);
TestA a2=new TestA(2);
TestA a3=new TestA(3);
TestB b1=new TestB(1);
TestB b2=new TestB(2);
TestB b3=new TestB(3);
a1.addTestB(b1);
a1.addTestB(b2);
a1.addTestB(b3);
b2.addTestA(a1);
b2.addTestA(a2);
Session s = factory.openSession();
s = factory.openSession();
Session session = factory.openSession();
session.save(a1);
session.flush();
session.close();
}
测试后连接表的数据为:
testa testb
1 1
1 2
1 3
根据inverse规则,对这些代码:b2.addTestA(a1); b2.addTestA(a2); 建立的关系,数据库并没有存储下来,因为TestB没有责任维护这些关系,所以产生的sql语句自然不会有针对Testa_testB表的操作了。假设应用中真的需要这些方法,那么我们可以修改TestB的方法,让他们注意在维护端类中执行相应的操作以使得关系能够在数据库中保存下来,更改TestB如 下:/*
* Created on 2004-7-25
*
* To change the template for this generated file go to
* Window>Preferences>Java>Code Generation>Code and Comments
*/
package org.hibernate.auction;
import java.util.*;
/**
* @author Administrator
*
* To change the template for this generated type comment go to
* Window>Preferences>Java>Code Generation>Code and Comments
*/
public class TestB {
int id;
String name;
Set testAs=new HashSet();
public TestB(){
}
public TestB(int id){
setId(id);
}
public int getId(){
return id;
}
public void setId(int id){
this.id=id;
}
public String getName(){
return name;
}
public void setName(String name){
this.name=name;
}
public Set getTestAs(){
return testAs;
}
public void setTestAs(Set s){
testAs=s;
}
public void addTestA(TestA ta){
testAs.add(ta);
ta.addTestB(this);
}
public static void main(String[] args) {
}
}
那么测试执行后连接表的数据为:
testa testb
1 2
1 3
1 1
2 2
测试通过。
附 hibernate cascade备忘 :
当关联双方存在父子关系,就可以在 set 处设定 cascade 为 all-delete-orphan
所谓父子关系,即指由父方控制子方的持久化圣明周期,子方对象必须和一个父方对象关联。如果删除父方对象,应该级联删除所有关联的子方对象;如果一个子方对象不再和一个父方对象关联,应该把这个子方对象删除。
all-deleteorphan 的能力:
1. 当保存或更新父方对象时,级联保存或更新所有关联的子方对象,相当于 cascade 为 save-update
2. 当删除父方对象时,级联删除所有关联的子方对象,相当于 cascade 为 delete
3. 删除不再和父方对象关联的所有子方对象
解除父子关系的 java 语句例如:
customer.getOrders().remove(order);
order.setCustomer(null);
Arial;" />tx.commit();
如果 cascade 属性取默认值 null,当解除父子关系时,会执行如下 sql:
update ORDER set CUSTOMER_ID=null where ID=2
inverse 设定的原则:
1. 在映射一对多双向关联关系时,应该设定 many 方的 inverse 为 true,以提高性能
2. 在建立两个对象的双向关联时,应同时修改关联两端的对象的相应属性:
1)customer.getOrders().add(order);
2)order.setCustomer(customer);
如果不执行 1)而仅执行 2),由于 set 元素的 inverse 为 true,因此 hibernate 不会按照 CUSTOMER 对象的状态变化来同步数据库。
inverse 解决性能问题的例子:
1. 建立 Order 到 Customer 的多对一关联关系
order.setCustomer(customer);
相应执行的 SQL 为:
update ORDERS set ORDER_NUMBER=''''Jack_Order001'''', CUSTOMER_ID=2 where ID=2;
2. 建立 Customer 到 Order 的一对多关系
customer ORDERS set CUSTOMER_ID=2 where ID=2;
/>相应 SQL 为:
update ORDERS set CUSTOMER_ID=2 where ID=2;
显然 1 和 2 的 SQL 功能重复了,反复执行这样的 SQL 语句会引起性能下降,因此:
inverse 设定为 true 时,声明 Customer 端的关联只是 Order 端关联的镜像。当两者状态发生变化时,Hibernate 仅按照 Order 对象状态变化来同步数据库。即仅会执行以下 SQL:
update ORDERS set ORDER_NUMBER=''''Jack_Order001'''', CUSTOME_ID=2 where ID=2;
Customer.hbm.xml 片段如下:
<set
name="orders"
cascade="all-delete-orphan"
inverse="true"
>
<key column="CUSTOMER_ID" />
<one-to-many class="mypack.Order" />
</set>
分享到:
相关推荐
### Hibernate Inverse 和 Cascade 的详细讲解 #### 一、引言 在ORM(Object-Relational Mapping)领域,Hibernate作为一款流行的Java持久层框架,它提供了丰富的API和配置选项来帮助开发者实现对象与数据库表之间...
Hibernate中cascade与inverse属性详解
Hibernate中Inverse和Cascade的区别.html
在Java的持久化框架Hibernate中,级联操作(Cascade)和反转(Inverse)是两个重要的概念,它们主要用于管理对象关系模型中的关联关系。在一对多的关系中,这些特性可以帮助简化数据操作,提高代码的可读性和维护性...
在 Hibernate 框架中,`cascade` 和 `inverse` 是两个重要的概念,它们主要用于管理对象之间的持久化关系,特别是涉及到一对一(one-to-one)、一对多(one-to-many)和多对多(many-to-many)关系时。这两个属性都...
在深入探讨Hibernate集合映射中的`inverse`与`cascade`属性之前,我们首先需要理解Hibernate框架的基本概念。Hibernate是一个开放源代码的对象关系映射(ORM)框架,它为Java应用程序提供了一种将对象模型与数据库...
### Hibernate中的Cascade选项详解 #### 一、概述 在Hibernate框架中,cascade选项提供了一种管理实体间关联的便捷方式,使得对一个实体的操作能够自动地应用到与之相关的其他实体上。这对于处理复杂的数据库关系...
本文将深入探讨Hibernate中的一对多关系,并重点解析`inverse`属性的作用及其应用。 一对多关系是数据库设计中常见的关联类型,例如一个用户可以拥有多个订单,一个班级可以包含多个学生等。在Hibernate中,通过...
如果我们在ORM工具如Hibernate中定义这种关系,可以设置其中一个关联为“inverse”,表示这个关联的维护责任不在该端。换句话说,更新或删除部门时,相关的员工记录不会被自动更新或删除,反之亦然。这样可以避免...
总结起来,`cascade`和`inverse`是Hibernate中用于管理对象关联关系的重要属性,它们共同确保了数据的一致性和操作的便捷性。在实际应用中,需要根据业务逻辑和性能需求,合理设置这两个属性,以达到最佳的数据库...
在探讨Hibernate框架中的级联操作(cascade)与控制权反转(inverse)之前,我们需要先对Hibernate有一个基本的理解。Hibernate是一个开放源代码的对象关系映射(ORM)框架,它为Java应用提供了一种将对象模型映射到...
本篇将深入讲解“cascade”和“inverse”这两个重要的概念,以及它们在实际应用中的作用。 首先,让我们理解一下“关联映射”。在Hibernate中,关联映射允许我们将Java对象与数据库表的记录进行关联。例如,一个...
描述提到“使用cascade和inverse优化区和街道关联关系”,这意味着我们将深入理解Hibernate的cascade和inverse属性,以及它们在双向一对多关联关系中的应用。 Hibernate是Java领域中广泛使用的对象关系映射(ORM)...
### Hibernate中的Inverse属性详解 在Hibernate框架中,`inverse`属性是用于管理对象关系的一方在持久化操作中是否承担删除或更新关联的责任。当两个实体之间存在双向关联时(如一对多或许多对一的关系),`inverse...
在Hibernate中,`cascade`和`inverse`是两个重要的概念,它们涉及到对象之间的关系管理和数据持久化。 **1. Hibernate Cascade** `cascade`属性主要用于控制对象间的级联操作。当在主对象上执行保存、更新、删除等...
理解并正确使用Hibernate的`cascade`和`inverse`属性对于优化数据操作和避免数据一致性问题至关重要。在实际开发中,应根据业务逻辑和数据模型谨慎设定这些属性,以确保数据操作的正确性和高效性。
- **一对多(OneToMany)**:使用`<list>`、`<set>`或`<bag>`,并通过`inverse`属性指定维护端,`cascade`属性控制级联操作。 - **多对一(ManyToOne)**:通过`<many-to-one>`标签,指定引用的目标实体类以及引用...
在Hibernate这个强大的对象关系映射(ORM)框架中,`inverse`属性是一个非常重要的概念,它主要用于管理关联关系的维护责任。在这个例子中,我们将会深入理解`inverse`属性的作用,并通过一个简单的测试案例——`...