1.双向1:n关联(常用,非常重要)
对于1-N关联,Hibernate推荐使用双向关联,而且不要让1的一端控制关联关系,而使用N的一端控制关联关系。
双向的N-1关联与1-N关联是完全相同的两种情形。两端都需要增加对关联属性的访问,N的一端增加引用到关联实体的属性,1的一端增加集合属性,集合元素为关联实体。
采用一对多双向关联映射的目的主要是为了主要是为了解决一对多单向关联的缺陷而不是需求驱动的。
一对多双向关联的映射方式:
**在一的一端的集合上采用< key>标签,在多的一端加入一个外键**
**在多的一端采用< many-to-one>标签**
**注意:**< key>标签和< many-to-one>标签加入的字段保持一直,否则会产生数据混乱
域模型
从 Order 到 Customer 的多对一双向关联需要在Order 类中定义一个 Customer 属性, 而在 Customer 类中需定义存放 Order 对象的集合属性
关系数据模型
ORDERS 表中的 CUSTOMER_ID 参照 CUSTOMER 表的主键
注意
当Session从数据库中加载Java集合时,创建的是Hibernate内置集合类的实例,因此,在持久化类中定义集合属性时,必须把属性声明为Java接口
Hibernate的内置集合类具有集合代理功能,支持延迟检索策略
事实上,Hibernate的内置集合类封装了JDK中的集合类,这使得Hibernate能够对缓存中的集合对象进行脏检查,按照集合对象的状态来同步更新数据库。
在定义集合属性时,通常把它初始化为集合实现类的一个实例,这样可以提高程序的健壮性,避免应用程序访问取值为null的集合的方法。
例如:private Set orders = new HashSet< Order>();
Demo
实体对象
public class Customer {
private Integer customerId;
private String customerName;
private Set<Order> orders = new HashSet<Order>();
//省去get和set
}
public class Order {
private Integer orderId;
private String orderName;
private Customer customer;
//省去get和set
}
Customer.hbm.xml
<hibernate-mapping package="com.lihui.hibernate.double_n_1">
<class name="Customer" table="CUSTOMERS">
<id name="customerId" type="java.lang.Integer">
<column name="CUSTOMER_ID" />
<generator class="native" />
</id>
<property name="customerName" type="java.lang.String">
<column name="CUSTOMER_NAME" />
</property>
<set name="orders" inverse="true">
<key column="CUSTOMER_ID"></key>
<one-to-many class="Order"/>
</set>
</class>
</hibernate-mapping>
set
name属性: 设定待映射的持久化类的属性的
inverse 属性:
在hibernate中通过对 inverse 属性的来决定是由双向关联的哪一方来维护表和表之间的关系。 inverse = false 的为主动方,inverse = true 的为被动方, 由主动方负责维护关联关系。在没有设置 inverse=true 的情况下,父子两边都维护父子关系
在 1-N 关系中,将 N 方设为主控方将有助于性能改善(如果要国家元首记住全国人民的名字,不是太可能,但要让全国人民知道国家元首,就容易的多)
在 1-N 关系中,若将 1 方设为主控方,会额外多出 update 语句。插入数据时无法同时插入外键列,因而无法为外键列添加非空约束.
order-by 属性:
如果设置了该属性, 当 Hibernate 通过 select 语句到数据库中检索集合对象时, 利用 order by 子句进行排序
order-by 属性中还可以加入 SQL 函数例如:
key
设定与所关联的持久化类对应的表的外键
column: 指定关联表的外键名
one-to-many
设定集合属性中所关联的持久化类
class: 指定关联的持久化类的类名
Order.hbm.xml
<hibernate-mapping package="com.lihui.hibernate.double_n_1">
<class name="Order" table="ORDERS">
<id name="orderId" type="java.lang.Integer">
<column name="ORDER_ID" />
<generator class="native" />
</id>
<property name="orderName" type="java.lang.String">
<column name="ORDER_NAME" />
</property>
<many-to-one name="customer" class="Customer" cascade="all" column="CUSTOMER_ID"></many-to-one>
</class>
</hibernate-mapping>
2.单向n:1关联
原理:
多对一关联映射原理:在多的一端加入一个外键,指向一的一端
单向N-1关系,比如多个人对应一个地址,只需从人实体端可以找到对应的地址实体,无须关系某个地址的全部住户。
单向 n-1 关联只需从 n 的一端可以访问 1 的一端。
域模型
从 Order 到 Customer 的多对一单向关联需要在Order 类中定义一个 Customer 属性, 而在 Customer 类中无需定义存放 Order 对象的集合属性
关系数据模型
ORDERS 表中的 CUSTOMER_ID 参照 CUSTOMER 表的主键
Demo
Hibernate 使用 元素来映射多对一关联关系< many-to-one name=”customer” class=”Customer” column=”CUSTOMER_ID” cascade=”all” />
name: 设定待映射的持久化类的属性的名字
column: 设定和持久化类的属性对应的表的外键
class:设定待映射的持久化类的属性的类型
cascade:意味着系统将先自动级联插入主表记录,也就是说先持久化Customer对象,再持久化Person对象。开发时不建议使用该属性,建议使用手工的方式。
下面是实体对象,分为Customer(顾客)和Order(订单),其中订单和顾客是N-1关系。
public class Customer {
private Integer customerId;
private String customerName;
//省去get和set方法
}
public class Order {
private Integer orderId;
private String orderName;
private Customer customer;
//省去get和set方法
}
Customer.hbm.xml 一的一方
<hibernate-mapping>
<class name="com.lihui.hibernate.single_n_1.Customer" table="CUSTOMERS">
<id name="customerId" type="java.lang.Integer">
<column name="CUSTOMER_ID" />
<generator class="native" />
</id>
<property name="customerName" type="java.lang.String">
<column name="CUSTOMER_NAME" />
</property>
</class>
</hibernate-mapping>
Order.hbm.xml 多的一方
<hibernate-mapping package="com.lihui.hibernate.single_n_1">
<class name="Order"
table="ORDERS">
<id name="orderId" type="java.lang.Integer">
<column name="ORDER_ID" />
<generator class="native" />
</id>
<property name="orderName" type="java.lang.String">
<column name="ORDER_NAME" />
</property>
<many-to-one name="customer" class="Customer" column="CUSTOMER_ID" cascade="all" />
</class>
</hibernate-mapping>
Junit Test由于在Order.hbm.xml中配置了cascade=”all”,所以只需要保存order对象即可,会首先自动保存级联的Customer对象。
@Test
public void testSave() {
Customer customer = new Customer();
customer.setCustomerName("a");
Order order1 = new Order();
order1.setOrderName("A");
order1.setCustomer(customer);
Order order2 = new Order();
order2.setOrderName("B");
order2.setCustomer(customer);
session.save(order1);
session.save(order2);
}
3.单向1:n关联(有缺陷不常用)
一对多关联映射和多对一关联映射原理是一致的,都是在多的一端加入一个外键,指向一的一端。
注意:它与多对一的区别是维护的关系不同
多对一维护的关系是:多指向一的关系,有了此关系,加载多的时候可以将一加载上来
一对多维护的关系是:一指向多的关系,有了此关系,在加载一的时候可以将多加载上来
关键映射代码——在一的一端加入如下标签映射:
<set name="customer">
<key column="classesid"/>
<one-to-many class="com.hibernate.Customer"/>
</set>
缺陷:
因为多的一端Student不知道Classes的存在(也就是Student没有维护与Classes的关系)所以在保存Student的时候关系字段classesid是为null的,如果将该关系字段设置为非空,则将无法保存数据,常用解决办法是改用双向关联映射
参考:https://www.w3cschool.cn/hibernate_articles/yr6f1ioh.html
http://blog.csdn.net/huangaigang6688/article/details/7761310