Hibernate中的inverse详解

场景:customer和order 一对多双向关联

[java]  view plain copy
  1. public class Order {  
  2.     private Long orderId;  
  3.     private String orderDetail;  
  4.     private Customer customer;  
  5.     public Order(){  
  6.     }  
  7.     public Order(String orderDetail){  
  8.         this.orderDetail=orderDetail;  
  9.     }  
  10.     public Long getOrderId() {  
  11.         return orderId;  
  12.     }  
  13.     public void setOrderId(Long orderId) {  
  14.         this.orderId = orderId;  
  15.     }  
  16.     public String getOrderDetail() {  
  17.         return orderDetail;  
  18.     }  
  19.     public void setOrderDetail(String orderDetail) {  
  20.         this.orderDetail = orderDetail;  
  21.     }  
  22.     public Customer getCustomer() {  
  23.         return customer;  
  24.     }  
  25.     public void setCustomer(Customer customer) {  
  26.         this.customer = customer;  
  27.     }  
  28. }  

[java]  view plain copy
  1. public class Customer {  
  2.     private Long customerId;  
  3.     private String customerName;  
  4.     private Set<Order> orders=new HashSet<Order>();  
  5.     public Customer(){}  
  6.     public Customer(String customerName){  
  7.         this.customerName=customerName;  
  8.     }  
  9.     public Long getCustomerId() {  
  10.         return customerId;  
  11.     }  
  12.     public void setCustomerId(Long customerId) {  
  13.         this.customerId = customerId;  
  14.     }  
  15.     public String getCustomerName() {  
  16.         return customerName;  
  17.     }  
  18.     public void setCustomerName(String customerName) {  
  19.         this.customerName = customerName;  
  20.     }  
  21.     public Set<Order> getOrders() {  
  22.         return orders;  
  23.     }  
  24.     public void setOrders(Set<Order> orders) {  
  25.         this.orders = orders;  
  26.     }  
  27. }  

Customer.hbm.xml

[html]  view plain copy
  1. <hibernate-mapping>  
  2.     <class name="entity.Customer" table="customers">  
  3.         <id name="customerId" type="long" column="customer_id">  
  4.             <generator class="identity"></generator>  
  5.         </id>  
  6.         <property name="customerName" type="string" column="customer_name"  
  7.             not-null="true" length="20" />  
  8.         <set name="orders" cascade="save-update">  
  9.             <key column="customer_id"></key>  
  10.             <one-to-many class="entity.Order"/>  
  11.         </set>  
  12.     </class>  
  13. </hibernate-mapping>   

Order.hbm.xml

[html]  view plain copy
  1. <hibernate-mapping>  
  2.     <class name="entity.Order" table="orders">  
  3.         <id name="orderId" type="long" column="order_id">  
  4.             <generator class="identity"></generator>  
  5.         </id>  
  6.         <property name="orderDetail" type="string" column="order_detail"  
  7.             not-null="true" length="20" />  
  8.         <many-to-one name="customer" column="customer_id"  
  9.         class="entity.Customer"  lazy="false"/>   
  10.     </class>  
  11. </hibernate-mapping>   


实验:

(1).saveCustomerAndOrderSeparely()方法,先创建一个Customer和Order对象,不建立他们的关联,最后分别持久化这两个对象

(注意:此时 order.hbm.xml中的many-to-one没有not-null属性,即其属性默认为false,这样可以保证不违反主键非空约束)

[java]  view plain copy
  1. public void saveCustomerAndOrderSeparely(){  
  2.         Session session=null;  
  3.         Transaction tx=null;  
  4.         try{  
  5.             session=HibernateSessionFactory.getSession();     
  6.               
  7.             Customer customer=new Customer("tom");        
  8.             Order order1=new Order("order1");  
  9.               
  10.             tx=session.beginTransaction();  
  11.             session.save(customer);  
  12.             session.save(order1);  
  13.             tx.commit();  
  14.         }catch(Exception e){  
  15.             e.printStackTrace();  
  16.             tx.rollback();  
  17.         }finally{  
  18.             session.close();  
  19.         }  
  20.     }  

运行该方法将执行一下两条insert 语句:

insert into customer(customer_id,customer_name) values(1,"tom");

insert into orders(order_id,order_name) values(1,"order1",null);

(2)先加载持久化对象Customer和Order对象,然后建立两者的一对多双向关联关系:

[java]  view plain copy
  1. public void associateCustomerAndOrder(){  
  2.         Session session=null;  
  3.         Transaction tx=null;  
  4.         try{  
  5.             session=HibernateSessionFactory.getSession();  
  6.             tx=session.beginTransaction();  
  7.             Customer customer=(Customer)session.load(Customer.class, (long)1);  
  8.             Order order=(Order)session.load(Order.class,(long)1);  
  9.             //建立customer和order关联  
  10.             order.setCustomer(customer);  
  11.             customer.getOrders().add(order);  
  12.             tx.commit();  
  13.         }catch(Exception e){  
  14.             e.printStackTrace();  
  15.             tx.rollback();  
  16.         }finally{  
  17.             session.close();  
  18.         }  
  19.     }  

Hibernate会自动清理缓存中的所有持久化对象, 按照持久化对象的属性变化来同步更新数据库。 如果把Customer.hbm.xml中的<set>元素的inverse属性设置为false,那么hibernate在清理以上Customer对象和Order对象是执行一下两条sql语句:

update orders set order_detail='tom',customer_id=1 where order_id=1;

update orders set customer_id=1 where order_id=2;

尽管实际上只是操作了orders表的一条记录,但是以上sql语句表明hibernate执行了两次update操作。这是因为hibernate根据内存中持久化对象的属性变化来决定需要执行那些sql语句。当建立order对象和customer对象的双向关联关系时,需要程序中分别修改这两个对象的属性:

(1)修改Order对象,建立order对象到customer对象的多对一关联关系:

order.setCustomer(customer);

Hibernate探测到持久化对象Order的属性的上述变化后,执行相应的sql语句为:

update orders set order_detail='tom',customer_id=1 where order_id=1;

(2)修改Customer对象,建立Customer对象到Order对象的一对多关联关系:

customer.getOrders().add(order);

Hibernate探测到持久化对象Customer的属性的上述变化,执行相应的sql语句:

update orders set customer_id=1 where order_id=2;

重复的执行多余的sql语句会影响java应用的性能,解决这一问题的办法是把<set>元素的inverse属性设置为true,该属性默认为false;

<set name="orders" cascade="save-update" inverse="true">
<key column="customer_id"></key>
<one-to-many class="entity.Order"/>
</set>

以上代码表示在Customer和Order的双向关联中,customer端的关联只是order端关联的镜像。当Hibernate探测到持久化对象Customer和Order的属性均发生变化时,仅按照Order对象的属性的变化同步更新数据库。

按照上述方法修改Customer.hbm.xml文件,在运行associateCustomerAndOrder()方法,Hibernate只执行一条sql语句:

session=HibernateSessionFactory.getSession();
tx=session.beginTransaction();
Customer customer=(Customer)session.load(Customer.class, (long)1);
Order order=(Order)session.load(Order.class,(long)1);
order.setCustomer(customer);
//customer.getOrders().add(order);
tx.commit();

如果对associateCustomerAndOrder方法做如下修改

[java]  view plain copy
  1. session=HibernateSessionFactory.getSession();  
  2.             tx=session.beginTransaction();  
  3.             Customer customer=(Customer)session.load(Customer.class, (long)1);  
  4.             Order order=(Order)session.load(Order.class,(long)1);  
  5.             order.setCustomer(customer);  
  6.             <strong>//customer.getOrders().add(order);</strong>  
  7.             tx.commit();  

以上代码仅设置了Order对象的customer属性,hibernate仍然会按照Order对象的属性变化来同步更新数据库,执行一下sql:

update orders set order_detail='tom',customer_id=1 where order_id=1;

如果对associateCustomerAndOrder方法做如下修改

[java]  view plain copy
  1. session=HibernateSessionFactory.getSession();  
  2.             tx=session.beginTransaction();  
  3.             Customer customer=(Customer)session.load(Customer.class, (long)1);  
  4.             Order order=(Order)session.load(Order.class,(long)1);  
  5.             <strong>//order.setCustomer(customer);</strong>  
  6.             customer.getOrders().add(order);  
  7.             tx.commit();  

以上代码仅设置了customer对象的orders属性,由于<set>元素的inverse属性为true,因此Hibernate不会按照Customer对象的属性变化来同步更新数据库。

根据上述实验,可以得出这样的结论:

〈1〉在映射一对多双向关联关系时,应该将"one"方把<set>元素的inverse属性设置为true,可以提高应用性能。

〈2〉在建立两个对象的双向关联时,应该同时修改关联对象两端对象的相应属性。

order.setCustomer(customer);
customer.getOrders().add(order);

这样才会使程序更加健壮,提高业务逻辑曾的独立性,使业务逻辑层的代码不受hibernate实现的影响。同理,当解除双向关联的关系时,也应该修改关联两段的对象的相应属性:

customer.getOrders().remove(order);

order.setCustomer(null);

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值