`

HIbernate中inverse的用法

阅读更多
Always put inverse=”true” in your collection variable ?
There are many Hibernate articles try to explain the “inverse” with many Hibernate “official” jargon, which is very hard to understand (at least to me). In few articles, they even suggested that just forget about what is “inverse”, and always put inverse=”true” in the collection variable.

This statement is always true – “put inverse=true in collection variable”, but do not blindfold on it, try to understand the reason behind is essential to optimal your Hibernate performance.

 

What is “inverse” ?

This is the most confusing keyword in Hibernate, at least i took quite a long time to understand it. The “inverse” keyword is always declare in one-to-many and many-to-many relationship (many-to-one doesn’t has inverse keyword), it means which side is responsible to take care of the relationship.

 

“inverse”, should change to “relationship owner”?

In Hibernate, only the “relationship owner” should maintain the relationship, and the “inverse” keyword is created to defines which side is the owner to maintain the relationship. However the “inverse” keyword itself is not verbose enough, I would suggest change the keyword to “relationship_owner“.

In short, inverse=”true” means this is the relationship owner, and inverse=”false” (default) means it’s not.

 

 

举例如下

Customer类:
public class Customer { 
	private int id; 
	private String name;
private Set orders = new HashSet();
//getter / setter
}

即Customer类具有一个set集合属性orders,其中Order是一个普通的类:
public class Order { 
	private int id; 
	private String orderName;
//getter / setter
}

数据库中表的结构:
t_customer:  两个字段:id  name
t_order:     三个字段:id  orderName  customerid


Customer类的映射文件:Customer.hbm.xml  (Order类的映射文件忽略)
<hibernate-mapping>
	<class name="test.Customer" table="t_customer" lazy="false">  
		<id name="id"> 
		   <generator class="native"/>
		</id>  
		<property name="name"/>  
		<set name="orders"  cascade="save-update"  lazy="false">
		   <key column="customerid"/>
		   <one-to-many class="test.Order"/>
		</set>
    </class> 
</hibernate-mapping>

执行如下代码:
Set orders = new HashSet(); 
			
Order o1 = new Order();
o1.setOrderName("o1"); 
Order o2 = new Order();
o2.setOrderName("o2");	 
orders.add(o1);
orders.add(o2);  	
			
Customer c = new Customer();
c.setName("aaa");
c.setOrders(orders);  

session.save(c); 

此时Hibernate发出的sql语句如下:
Hibernate: insert into t_customer (name) values (?)
Hibernate: insert into t_order (orderName) values (?)
Hibernate: insert into t_order (orderName) values (?)
Hibernate: update t_order set customerid=? where id=?
Hibernate: update t_order set customerid=? where id=?

查看数据库:
t_customer :                    t_order:   

id   |  name                   id   |   orderName   |   customerid 
1       aaa                    1           o1              1
                               2           o2              1 

保存Customer对象时,首先发出insert into t_customer (name) values (?)语句将c同步到数据库,由于在<set>映射中设置cascade="save-update",所以会同时保存orders集合中的 Order类型的o1,o2对象(如果没有这个设置,即cascade="save-update"),那么Hibenrate不会自动保存orders 集合中的对象,那么在更新时将会抛出如下异常:
Hibernate: insert into t_customer (name) values (?)
Hibernate: update t_order set customerid=? where id=?
org.hibernate.TransientObjectException: test.Order
••••••

抛出这一异常的原因是:<set>映射默认"inverse=fasle"即由Customer对象作为主控方,那么它要负责关联的 维护工作,在这里也就是负责更新t_order表中的customerid字段的值,但由于未设置cascade="save-update",所以 orders集合中的对象不会在保存customer时自动保存,因此会抛出异常(如果未设置,需要手动保存)。
现在设置cascade="save-update",同时设置inverse="true",即:
•••
<set name="orders" cascade="save-update" inverse="true" lazy="false">
	<key column="customerid"/>
	<one-to-many class="test.Order"/>
</set>  
•••

同样执行上述代码,发出如下语句:
Hibernate: insert into t_customer (name) values (?)
Hibernate: insert into t_order (orderName) values (?)
Hibernate: insert into t_order (orderName) values (?)

相比上一次执行,少了两条update语句,查看数据库:
t_customer :                    t_order:   

id   |  name                   id   |   orderName   |   customerid 
1       aaa                    1           o1              NULL
                               2           o2              NULL

发现t_order表中customerid的值为NULL,这是由于设置了inverse="true",它意味着
Customer不再作为主控方,而将关联关系的维护工作交给关联对象Orders来完成。在保存Customer时,Customer不在关心 Orders的customerid属性,必须由Order自己去维护,即设置order.setCustomer(customer);

如果需要通过Order来维护关联关系,那么这个关联关系转换成双向关联。
修改Order类代码:
public class Order { 
	private int id; 
	private String orderName;  
	private Customer customer;
•••
}

Order.hbm.xml:
<hibernate-mapping>
	<class name="test.Order" table="t_order">  
		<id name="id"> 
		   <generator class="native"/>
		</id>  
		<property name="orderName"/>   
		<many-to-one name="customer" column="customerid"/> 
    </class> 
</hibernate-mapping>

此时数据库中表的结构不会变化。

再次执行上述代码,发出如下sql语句:
Hibernate: insert into t_customer (name) values (?)
Hibernate: insert into t_order (orderName, customerid) values (?, ?)
Hibernate: insert into t_order (orderName, customerid) values (?, ?) 

发现在保存Order对象时为customerid字段赋值,因为Order对象中拥有Customer属性,对应customerid字段,查看数据库表:
t_customer :                    t_order:   

id   |  name                   id   |   orderName   |   customerid 
1       aaa                    1           o1              NULL
                               2           o2              NULL

发现customerid的值仍为NULL,因为在上述代码中并未设置Order对象的Customer属性值,由于设置了inverse="true",所以Order对象需要维护关联关系,所以必须进行设置,即
order.setCustomer(customer);

修改上述代码为:
•••
Customer c = new Customer();
			
Set orders = new HashSet(); 
Order o1 = new Order();
o1.setOrderName("o1"); 
o1.setCustomer(c);
Order o2 = new Order();
o2.setOrderName("o2");
o2.setCustomer(c);
orders.add(o1);
orders.add(o2);  	
			
c.setName("aaa");
c.setOrders(orders); 
			
session.save(c); 
••• 
 

执行上述代码,发出如下语句:
Hibernate: insert into t_customer (name) values (?)
Hibernate: insert into t_order (orderName, customerid) values (?, ?)
Hibernate: insert into t_order (orderName, customerid) values (?, ?)

查看数据库:
t_customer :                    t_order:   

id   |  name                   id   |   orderName   |   customerid 
1       aaa                    1           o1              1
                               2           o2              1

发现已经设置了customerid的值。

在一对多关联中,在一的一方设置inverse="true",有助于性能的改善。通过上述分析可以发现少了update语句。

 

分享到:
评论

相关推荐

    hibernate inverse和cascade的详细讲解

    对于`one-to-one`和`many-to-one`关系,它们仅包含单个对象的引用,因此不需要使用`inverse`。 - **Inverse 的值** - **默认值**:`inverse`的默认值为`false`,表示对集合对象的修改会被反映到数据库中。 - **`...

    hibernate集合映射inverse和cascade详解.txt

    在深入探讨Hibernate集合映射中的`inverse`与`cascade`属性之前,我们首先需要理解Hibernate框架的基本概念。Hibernate是一个开放源代码的对象关系映射(ORM)框架,它为Java应用程序提供了一种将对象模型与数据库...

    Hibernate_级联关系说明_-_关于cascade和inverse的用法

    在探讨Hibernate框架中的级联操作(cascade)与控制权反转(inverse)之前,我们需要先对Hibernate有一个基本的理解。Hibernate是一个开放源代码的对象关系映射(ORM)框架,它为Java应用提供了一种将对象模型映射到...

    hibernate 级联(cascade和inverse)一对多

    在Java的持久化框架Hibernate中,级联操作(Cascade)和反转(Inverse)是两个重要的概念,它们主要用于管理对象关系模型中的关联关系。在一对多的关系中,这些特性可以帮助简化数据操作,提高代码的可读性和维护性...

    inverse和cascade使用阐述

    如果我们在ORM工具如Hibernate中定义这种关系,可以设置其中一个关联为“inverse”,表示这个关联的维护责任不在该端。换句话说,更新或删除部门时,相关的员工记录不会被自动更新或删除,反之亦然。这样可以避免...

    Hibernate电子书(全)

    在关系数据库中,集合类型的数据(如Set、List、Map)不能直接存储,而Hibernate提供了将这些集合类型映射到数据库中的机制,如使用`Set`和`Map`映射关联关系,这使得Java对象的集合属性可以直接与数据库中的记录...

    Hibernate开发租房系统2 源码

    描述提到“使用cascade和inverse优化区和街道关联关系”,这意味着我们将深入理解Hibernate的cascade和inverse属性,以及它们在双向一对多关联关系中的应用。 Hibernate是Java领域中广泛使用的对象关系映射(ORM)...

    hibernate bag 集合映射

    标题中的“hibernate bag 集合映射”指的是Hibernate框架中的一种关系映射机制。Hibernate是一个流行的Java ORM(对象关系映射)框架,它允许开发者将数据库表与Java类进行映射,使得在处理数据库操作时可以使用面向...

    hibernate的联合主键怎么设置

    - 相反,如果两边都是 `inverse="false"` 或者默认值,Hibernate 会在每次关联的添加或删除时,都在中间表中进行相应的插入和删除操作,可能会导致重复的插入。 因此,通常我们会根据业务逻辑来合理设置 `inverse`...

    Hibernate中文帮助文档

    本中文帮助文档详细介绍了Hibernate的核心概念、配置、API使用以及最佳实践,是学习和掌握Hibernate不可或缺的参考资料。 1. **Hibernate概述**: - Hibernate是Java世界中最为流行的数据持久化框架之一,由Jboss...

    hibernate的延迟检索在轻量级J2EE框架中的应用

    当执行`session.load(User.class, "1")`后,即使调用了`getAddresses()`方法,Hibernate也不会立即查询地址集合,除非显式地遍历集合或访问集合中的某个元素。 ```java User user = (User) session.load(User.class...

    hibernate中one2many映射

    在Hibernate的配置文件(hibernate.cfg.xml)中,我们需要指定使用的数据库类型(这里是MySQL)及连接参数: ```xml &lt;property name="hibernate.dialect"&gt;org.hibernate.dialect.MySQL5Dialect &lt;property name="...

    hibernate中many2many映射

    在本场景中,我们探讨的是如何在Hibernate中配置Many-to-Many映射,并使用MySQL数据库来存储数据。我们将通过映射文件和Domain对象来理解这一过程。 首先,我们需要了解Many-to-Many关系的基本概念。在关系数据库中...

    hibernate中文参考文档

    - **多对多(Many-to-Many)**: 使用`&lt;set&gt;`标签配合`inverse="true"`属性或`@ManyToMany`注解。 #### 八、高级特性 - **懒加载(Lazy Loading)**: 只有在真正需要的时候才加载关联对象的数据。 - **批量加载(Batch ...

    hibernate学习笔记

    在Hibernate中,`inverse`属性通常与双向关联的实体一起使用,它决定了哪一方实体在进行删除或更新关联时拥有控制权。例如,在一对多关系中,如果`inverse`属性被设置为`true`,那么这一方将不会主动触发对关联实体...

    gilead hibernate lazyload例子

    在Flex中使用Gilead和Hibernate的懒加载,首先需要确保在Hibernate配置文件中对关联实体设置了懒加载属性。例如,如果有一个`User`类和一个`Address`类,`User`中包含一个`List&lt;Address&gt;`,那么在`User`的映射文件中...

    Hibernate 多表映射关系配置

    以上就是 Hibernate 中的一对多、多对一和多对多关系的配置和使用方法。理解这些关系并正确配置它们是充分利用 Hibernate 框架的关键。在实际项目中,根据业务需求选择合适的关系映射方式,并灵活运用,能够简化...

Global site tag (gtag.js) - Google Analytics