hibernate中inverse详解

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

public class Order {
	private Long orderId;
	private String orderDetail;
	private Customer customer;
	public Order(){
	}
	public Order(String orderDetail){
		this.orderDetail=orderDetail;
	}
	public Long getOrderId() {
		return orderId;
	}
	public void setOrderId(Long orderId) {
		this.orderId = orderId;
	}
	public String getOrderDetail() {
		return orderDetail;
	}
	public void setOrderDetail(String orderDetail) {
		this.orderDetail = orderDetail;
	}
	public Customer getCustomer() {
		return customer;
	}
	public void setCustomer(Customer customer) {
		this.customer = customer;
	}
}

public class Customer {
	private Long customerId;
	private String customerName;
	private Set<Order> orders=new HashSet<Order>();
	public Customer(){}
	public Customer(String customerName){
		this.customerName=customerName;
	}
	public Long getCustomerId() {
		return customerId;
	}
	public void setCustomerId(Long customerId) {
		this.customerId = customerId;
	}
	public String getCustomerName() {
		return customerName;
	}
	public void setCustomerName(String customerName) {
		this.customerName = customerName;
	}
	public Set<Order> getOrders() {
		return orders;
	}
	public void setOrders(Set<Order> orders) {
		this.orders = orders;
	}
}

Customer.hbm.xml

<hibernate-mapping>
	<class name="entity.Customer" table="customers">
		<id name="customerId" type="long" column="customer_id">
			<generator class="identity"></generator>
		</id>
		<property name="customerName" type="string" column="customer_name"
			not-null="true" length="20" />
		<set name="orders" cascade="save-update">
			<key column="customer_id"></key>
			<one-to-many class="entity.Order"/>
		</set>
	</class>
</hibernate-mapping> 

Order.hbm.xml

<hibernate-mapping>
	<class name="entity.Order" table="orders">
		<id name="orderId" type="long" column="order_id">
			<generator class="identity"></generator>
		</id>
		<property name="orderDetail" type="string" column="order_detail"
			not-null="true" length="20" />
		<many-to-one name="customer" column="customer_id"
		class="entity.Customer"  lazy="false"/> 
	</class>
</hibernate-mapping> 


实验:

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

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

public void saveCustomerAndOrderSeparely(){
		Session session=null;
		Transaction tx=null;
		try{
			session=HibernateSessionFactory.getSession();	
			
			Customer customer=new Customer("tom");		
			Order order1=new Order("order1");
			
			tx=session.beginTransaction();
			session.save(customer);
			session.save(order1);
			tx.commit();
		}catch(Exception e){
			e.printStackTrace();
			tx.rollback();
		}finally{
			session.close();
		}
	}

运行该方法将执行一下两条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对象,然后建立两者的一对多双向关联关系:

public void associateCustomerAndOrder(){
		Session session=null;
		Transaction tx=null;
		try{
			session=HibernateSessionFactory.getSession();
			tx=session.beginTransaction();
			Customer customer=(Customer)session.load(Customer.class, (long)1);
			Order order=(Order)session.load(Order.class,(long)1);
			//建立customer和order关联
			order.setCustomer(customer);
			customer.getOrders().add(order);
			tx.commit();
		}catch(Exception e){
			e.printStackTrace();
			tx.rollback();
		}finally{
			session.close();
		}
	}

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方法做如下修改

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();

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

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

如果对associateCustomerAndOrder方法做如下修改

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();

以上代码仅设置了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);

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值