近来回顾Hibernate,对于单/双向和多对多一直是一个难点和不容易理解的地方,特此写博文以便回顾


所用工具:eclipse luna、MySQL、windows7

      先来说一下单向一对多,一对多,顾名思义,一个表中一条记录对应另一个表中的多条记录,如一个顾客可以有多个订单,而每一个订单只有一个顾客。这里就用顾客-订单建立持久化类模型和数据关联关系,Hibernate的配置文件省略,以节省篇幅

package com.demo.model;

public class Customer {

	private Integer id;
	private String name;

	get/set
}
package com.demo.model;

public class Orders {

	private Integer id;
	private String name;

	private Customer customer;

	get/set

}
<hibernate-mapping>
    <class name="com.demo.model.many2one.Customer" table="CUSTOMERS">
    
        <id name="id" type="java.lang.Integer">
            <column name="CUSTOMER_ID" />
            <generator class="native" />
        </id>
        
        <property name="name" type="java.lang.String">
            <column name="NAME" />
        </property>
        
    </class>
</hibernate-mapping>
<hibernate-mapping package="com.demo.model.many2one">
    <class name="Orders" table="ORDERS">
    
        <id name="id" type="java.lang.Integer">
            <column name="ORDER_ID" />
            <generator class="assigned" />
        </id>
        
        <property name="name" type="java.lang.String">
            <column name="NAME" />
        </property>
        
        <!-- 映射多对一 -->
        <!-- 
        	name:Order中对应的“一”的属性;
        	class:多对一中一那端对应的持久化类(POJO类);
        	column:会在Order对应的表中生成一个外键,关联的是给定的字段,通过column属性完成了多到一的映射
         -->
        <many-to-one name="customer" class="Customer"
	column="CUSTOMER_ID" foreign-key="FK_CUSTOMER_ID_ORDER_ID"></many-to-one>
        
    </class>
</hibernate-mapping>

      Customer没什么值得注意的,主要是在Order这边(因为本例中单向多对一是从Order到Customer),使用了<many-to-one>元素来进行多对一映射,可以增加foreign-key属性指定要生成的外键的名称,注意记得把hbm.xml加入到Hibernate的配置文件中

      下面来写几个小测试:

    @Test
	public void testSave() {
		Customer customer = new Customer();
		customer.setName("c-aa");
		
		Order order1 = new Order();
		order1.setName("o-aa");
		
		Order order2 = new Order();
		order2.setName("o-bb");
		
		// 设定关联关系
		order1.setCustomer(customer);
		order2.setCustomer(customer);
		
		// 保存 3个insert
//		session.save(customer);
//		session.save(order1);
//		session.save(order2);
		// 3个insert,2个update
		session.save(order1);
		session.save(order2);
		session.save(customer);
	}

为什么保存顺序不同,会多出2个update呢?

      这是因为先保存order时,外键并没有对应,而在保存customer后,关联关系出现了,此时order的外键有参照了,于是为了修改order的外键,发送了update语句,建议先保存无外键的一端

再来看看获取:

@Test
public void testGet() throws Exception{
	Order order = (Order) session.get(Order.class, 1);
	System.out.println(order.getName());
	
	Customer customer = order.getCustomer();
	System.out.println(customer.getClass());
}

这是控制台返回的结果:

Hibernate: 
    select
        order0_.ORDER_ID as ORDER_ID1_1_0_,
        order0_.NAME as NAME2_1_0_,
        order0_.CUSTOMER_ID as CUSTOMER3_1_0_ 
    from
        ORDERS order0_ 
    where
        order0_.ORDER_ID=?
o-aa
class com.demo.model.many2one.Customer_$$_jvst72a_1

      可能大家看这个sql语句很正常,order的名称也查出来了,但是有个问题是,order里是有个customer属性的,customer.getClass()返回的应该是Customer的全类名,但返回的是com.demo.model.many2one.Customer_$$_jvst72a_1,是一个代理对象,这是Hibernate的懒加载机制的缘故,即在真正用到customer的属性和方法时,才去真正从数据库获取对应的customer,当然,也有出现懒加载异常的可能性,这里稍微一提,不再作过多解释,读者感兴趣的话可以找一下相关的资料看一下

最后来看一下删除:

	@Test
	public void testDelete() throws Exception {
		Customer customer = (Customer) session.get(Customer.class, 1);	
		
//		session.delete(customer);// 会出现异常
		
		Order order1 = (Order) session.get(Order.class, 1);
		Order order2 = (Order) session.get(Order.class, 2);
		
		session.delete(order1);
		session.delete(order2);
		session.delete(customer);
	}

      至于为什么会出现异常的原因,大家应该都知道了吧:因为customer关联着两个order,无法直接删除customer,只有先删除相关联的order后再删除customer

      更新没有什么需要注意的地方,所以就不贴出代码了