HIbernate映射
HIbernate映射
映射组成关系
Hibernate 把持久化类的属性分为两种:
值(value)类型: 没有 OID, 不能被单独持久化, 生命周期依赖于所属的持久化类的对象的生命周期实体(entity)类型: 有 OID, 可以被单独持久化, 有独立的生命周期
显然无法直接用 property 映射 pay 属性
Hibernate 使用 < component> 元素来映射组成关系,
该元素表名 pay 属性是 Worker 类一个组成部分, 在 Hibernate 中称之为组件
public class Worker {
private Integer id;
private String name;
private Integer age;
private Pay pay;
}
public class Pay {
private Integer monthpay;
private Integer yearpay;
private Integer daypay;
}
<component name="pay" class="Pay">
<property name="monthpay" column="month_pay"></property>
<property name="daypay" column="day_pay"></property>
<property name="yearpay" column="year_pay"></property>
</component>
映射一对多关联关系
- 单向:
- 单向 n-1 关联只需从 n 的一端可以访问 1 的一端
- 域模型:
- 从 Order 到 Customer 的多对一单向关联需要在Order 类中定义一个 Customer 属性, 而在 Customer 类中无需定义存放 Order 对象的集合属性
- 关系数据模型:
- ORDERS 表中的 CUSTOMER_ID 参照 CUSTOMER 表的主键
以 Customer 和 Order 为例: 一个用户能发出多个订单, 而一个订单只能属于一个客户. 从 Order 到 Customer 的关联是多对一关联; 而从 Customer 到 Order 是一对多关联
Hibernate 使用 < many-to-one> 元素来映射多对一关联关系
<many-to-one name="customer" class="Customer">
<column name="CUSTOMER_ID" />
</many-to-one>
- 双向:
- 双向 1-n 与 双向 n-1 是完全相同的两种情形
- 双向 1-n 需要在 1 的一端可以访问 n 的一端, 反之依然.
- 域模型:
- 从 Order 到 Customer 的多对一双向关联需要在Order 类中定义一个 Customer 属性, 而在 Customer 类中需定义存放 Order 对象的集合属性
- 关系数据模型:
- ORDERS 表中的 CUSTOMER_ID 参照 CUSTOMER 表的主键
- 注意:
-
当 Session 从数据库中加载 Java 集合时, 创建的是 Hibernate 内置集合类的实例, 因此在持久化类中定义集合属性时必须把属性声明为 Java 接口类型
- Hibernate 的内置集合类具有集合代理功能, 支持延迟检索策略
- 事实上, Hibernate 的内置集合类封装了 JDK 中的集合类, 这使得 Hibernate 能够对缓存中的集合对象进行脏检查, 按照集合对象的状态来同步更新数据库。
Hibernate 使用 < set> 元素来映射 set 类型的属性
<set name="oders" table="ODER" inverse="true">
<key>
<column name="CUSTOMER_ID" />
</key>
<one-to-many class="model2.Oder" />
</set>
关于inverse属性:
- 在hibernate中通过对 inverse 属性的来决定是由双向关联的哪一方来维护表和表之间的关系. inverse = false 的为主动方,inverse = true 的为被动方, 由主动方负责维护关联关系
在没有设置 inverse=true 的情况下,父子两边都维护父子关系
在 1-n 关系中,将 n 方设为主控方将有助于性能改善(如果要国家元首记住全国人民的名字,不是太可能,但要让全国人民知道国家元首,就容易的多)
- 在 1-N 关系中,若将 1 方设为主控方
- 会额外多出 update 语句。
- 插入数据时无法同时插入外键列,因而无法为外键列添加非空约束
映射一对一关联关系
- 基于外键映射的 1-1
-
对于基于外键的1-1关联,其外键可以存放在任意一边,在需要存放外键一端,增加many-to-one元素。为many-to-one元素增加unique=“true” 属性来表示为1-1关联
-
另一端需要使用one-to-one元素,该元素使用 property-ref 属性指定使用被关联实体主键以外的字段作为关联字段
- 基于主键映射的 1-1
-
基于主键的映射策略:指一端的主键生成器使用 foreign 策略,表明根据”对方”的主键来生成自己的主键,自己并不能独立生成主键. 子元素指定使用当前持久化类的哪个属性作为 “对方”
-
采用foreign主键生成器策略的一端增加 one-to-one 元素映射关联属性,其one-to-one属性还应增加 constrained=“true” 属性;另一端增加one-to-one元素映射关联属性。
-
constrained(约束):指定为当前持久化类对应的数据库表的主键添加一个外键约束,引用被关联的对象(“对方”)所对应的数据库表主键
映射多对多关联关系
- n-n 的关联必须使用连接表
-
与 1-n 映射类似,必须为 set 集合元素添加 key 子元素,指定 CATEGORIES_ITEMS 表中参照 CATEGORIES 表的外键为 CATEGORIY_ID. 与 1-n 关联映射不同的是,建立 n-n 关联时, 集合中的元素使用 many-to-many. many-to-many 子元素的 class 属性指定 items 集合中存放的是 Item 对象, column 属性指定 CATEGORIES_ITEMS 表中参照 ITEMS 表的外键为 ITEM_ID
映射继承关系
Hibernate支持三种继承映射策略:
- 使用 subclass 进行映射:将域模型中的每一个实体对象映射到一个独立的表中,也就是说不用在关系数据模型中考虑域模型中的继承关系和多态。
- 使用 joined-subclass 进行映射: 对于继承关系中的子类使用同一个表,这就需要在数据库表中增加额外的区分子类类型的字段。
-
使用 union-subclass 进行映射:域模型中的每个类映射到一个表,通过关系数据模型中的外键来描述表之间的继承关系。这也就相当于按照域模型的结构来建立数据库中的表,并通过外键来建立表之间的继承关系。
subclass 的继承映射:
- 采用 subclass 的继承映射可以实现对于继承关系中父类和子类使用同一张表
- 因为父类和子类的实例全部保存在同一个表中,因此需要在该表内增加一列,使用该列来区分每行记录到低是哪个类的实例—-这个列被称为辨别者列(discriminator).
- 在这种映射策略下,使用 subclass 来映射子类,使用 class 或 subclass 的 discriminator-value 属性指定辨别者列的值
- 所有子类定义的字段都不能有非空约束。如果为那些字段添加非空约束,那么父类的实例在那些列其实并没有值,这将引起数据库完整性冲突,导致父类的实例无法保存到数据库中
<class name="Person" table="PERSON" discriminator-value="person">
<id name="id" type="java.lang.Integer">
<column name="ID" />
<generator class="native" />
</id>
<discriminator column="type"></discriminator>
<property name="name" type="java.lang.String">
<column name="NAME" />
</property>
<property name="age" type="java.lang.Integer">
<column name="AGE" />
</property>
<subclass name="Student" discriminator-value="student">
<property name="school" column="SCHOOL" type="java.lang.String"></property>
</subclass>
</class>
joined-subclass的继承映射
采用 joined-subclass 元素的继承映射可以实现每个子类一张表
采用这种映射策略时,父类实例保存在父类表中,子类实例由父类表和子类表共同存储。因为子类实例也是一个特殊的父类实例,因此必然也包含了父类实例的属性。于是将子类和父类共有的属性保存在父类表中,子类增加的属性,则保存在子类表中。
在这种映射策略下,无须使用鉴别者列,但需要为每个子类使用 key 元素映射共有主键。
子类增加的属性可以添加非空约束。因为子类的属性和父类的属性没有保存在同一个表中
<class name="Person" table="PERSON">
<id name="id" type="java.lang.Integer">
<column name="ID" />
<generator class="native" />
</id>
<property name="name" type="java.lang.String">
<column name="NAME" />
</property>
<property name="age" type="java.lang.Integer">
<column name="AGE" />
</property>
<joined-subclass name="Student" table="STUDENTS">
<key column="STUDENT_ID" ></key>
<property name="school" column="SCHOOL" type="java.lang.String"></property>
</joined-subclass>
</class>
union-subclass 继承映射
- 采用 union-subclass 元素可以实现将每一个实体对象映射到一个独立的表中。
- 子类增加的属性可以有非空约束 — 即父类实例的数据保存在父表中,而子类实例的数据保存在子类表中。
- 子类实例的数据仅保存在子类表中, 而在父类表中没有任何记录
- 在这种映射策略下,子类表的字段会比父类表的映射字段要多,因为子类表的字段等于父类表的字段、加子类增加属性的总和
- 在这种映射策略下,既不需要使用鉴别者列,也无须使用 key 元素来映射共有主键.
- 使用 union-subclass 映射策略是不可使用 identity 的主键生成策略, 因为同一类继承层次中所有实体类都需要使用同一个主键种子, 即多个持久化实体对应的记录的主键应该是连续的. 受此影响, 也不该使用 native 主键生成策略, 因为 native 会根据数据库来选择使用 identity 或 sequence.
<class name="Person" table="PERSONS">
<id name="id" type="java.lang.Integer">
<column name="ID" />
<generator class="hilo" />
</id>
<property name="name" type="java.lang.String">
<column name="NAME" />
</property>
<property name="age" type="java.lang.Integer">
<column name="AGE" />
</property>
<union-subclass name="Student" table="STUDENT">
<property name="school" type="java.lang.String" column="SCHOOL"></property>
</union-subclass>
</class>
三种继承映射的比较
推荐阅读
-
Hibernate Validator实现更简洁的参数校验及一个util
-
mybatis输入映射和输出映射实例详解
-
详解JAVAEE——SSH三大框架整合(spring+struts2+hibernate)
-
详解Python中映射类型的内建函数和工厂函数
-
详解Python中映射类型(字典)操作符的概念和使用
-
Spring MVC+FastJson+hibernate-validator整合的完整实例教程
-
如何自定义hibernate validation注解示例代码
-
vim利用map映射执行脚本配置分享
-
Hibernate使用中防止SQL注入的几种方案
-
JSP 中Hibernate实现映射枚举类型