--例子使用客户表和订单表,一个客户可以有多个订单,一个订单只能属于一个客户。下面以一对多双向关联关系为例:
public void saveCustomerAndOrderSeparately() {
Session session = sessionFactory.openSession();
Transaction tx;
try {
tx = session.beginTransaction();
Customer customer = (Customer)session.load(Customer.class, 1L);
Order order = (Order)session.load(Order.class, 1L);
//做order多对一costomer关联关系,
order.setCustomer(customer);
//做customer一对多order关联关系
customer.getOrders().add(order);
tx.commit();
} catch (RuntimeException e) {
throw e;
}
}
当事务提交的时候,hibernate自动会做清理缓存中持久化对象,按照持久化对象的属性变化来操作数据库,如果把Customer
对象.hbm.xml文件中set下inverse属性设置为false,那么hibernate在清理Customer,Order两对象时,会执行两条SQL语句。
(inverse表示:在关联关系中,由哪方负责维护此关联关系,false表示都由自己来维护此关联关系,true表示由对方负责关系维护)
order.setCustomer(customer);代码表示:set 修改order表中的一条记录。但以上表名hibernate会执行两次uodate语句,
这是因为hibernate根据内存中持久化对象属性变化来决定需要执行哪些SQL,当建立Order和Customer双向关联关系时,需要在程序
中分别修改两个对象的属性(前提双向关联时)。
1)、修改Order对象,建立Order对象到Customer对象的多对一关联关系
order.setCustomer(customer);
hibernate探测到持久化对象Order属性发生变化后,执行相应SQL为:
update Order set ORDER_NUMBER = 'jack_order001', CUSTOMER_ID=2 where ID=2;
2).修改Customer对象,建立Customer对象到Order对象的一对多关联关系
customer.getOrders().add(order);
hibernate探测到持久化对象Customer对象属性发生变化后,执行相应SQL为:
update Order SET CUSTOMER_ID=2 where 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="Order" />
</set>
以上代码表明在Customer和Order的双向关联关系中,Customer端关联只是Order关联的镜像,当hibernate探测到两对象属性
均发生变化时,仅按照order端属性变化同步更新数据库。
update Order set ORDER_NUMBER = 'jack_order001', CUSTOMER_ID=2 where ID=2;
根据以上实现,可以得出这样结论:
1、当hibernate映射一对多双向关联关系时,需在<set>一方inverse属性配置为true;可减少多余不必要SQL操作数据库
2、当建立双向关联关系时,应该同时修改关联两端的对象相应属性
做order多对一costomer关联关系,
order.setCustomer(customer);
做customer一对多order关联关系
customer.getOrders().add(order);
解除双向关联关系时,也应该修改关联两端对象的相应属性
customer.getOrders().remove(order);
order.setCustomer(null);