HIbernate中inverse的用法

本文深入解析了Hibernate框架中“inverse”属性的作用,并通过实例演示如何使用该属性优化一对多关系的性能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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语句。

 

内容概要:文章基于4A架构(业务架构、应用架构、数据架构、技术架构),对SAP的成本中心和利润中心进行了详细对比分析。业务架构上,成本中心是成本控制的责任单元,负责成本归集与控制,而利润中心是利润创造的独立实体,负责收入、成本和利润的核算。应用架构方面,两者都依托于SAP的CO模块,但功能有所区分,如成本中心侧重于成本要素归集和预算管理,利润中心则关注内部交易核算和获利能力分析。数据架构中,成本中心与利润中心存在多对一的关系,交易数据通过成本归集、分摊和利润计算流程联动。技术架构依赖SAP S/4HANA的内存计算和ABAP技术,支持实时核算与跨系统集成。总结来看,成本中心和利润中心在4A架构下相互关联,共同为企业提供精细化管理和决策支持。 适合人群:从事企业财务管理、成本控制或利润核算的专业人员,以及对SAP系统有一定了解的企业信息化管理人员。 使用场景及目标:①帮助企业理解成本中心和利润中心在4A架构下的运作机制;②指导企业在实施SAP系统时合理配置成本中心和利润中心,优化业务流程;③提升企业对成本和利润的精细化管理水平,支持业务决策。 其他说明:文章不仅阐述了理论概念,还提供了具体的应用场景和技术实现方式,有助于读者全面理解并应用于实际工作中。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值