场景: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);
- <strong>//customer.getOrders().add(order);</strong>
- 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);
- <strong>//order.setCustomer(customer);</strong>
- 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);