近来回顾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
更新没有什么需要注意的地方,所以就不贴出代码了