1.对象关系映射基础
1.1 持久化类的属性及访问方法
持久化类的访问方法有两个调用者:
- java应用程序:通过持久化类的getter和setter方法进行访问。
- Hibernate :通过持久化类的getter和setter方法或通过java的反射机制进行访问
注意:
java应用程序不能访问持久化类的private类型的getter、setter方法,而Hibernate可以。
持久化类中的属性类型可以是基本类型或包类型,他们对应相同的Hibernate映射类型。但基本类型无法表示null值,推荐使用包类型。
1.2 Hibernate访问持久化类属性的策略
通过设置映射文件中的<property>元素的access属性的方式。
- access="property"(默认),指定Hibernate通过setXXX和getXXX方法访问持久化类属性(最佳实践)。
- access="field",指定Hibernate通过java反射机制直接访问类的属性。
1.3 派生属性的映射
派生属性:持久化类的某些属性的值在运行时通过计算得出。
1)在持久化类中虽没有某个属性,表中有这个属性。
解决:在持久化类中设置该属性对应的setter和getter方法,并加入处理逻辑,然后在映射文件中映射该属性,则Hibernate就可以访问。
2)持久化类中有某个属性如avgAge,但表中没有该属性。
1.4 控制Hibernate生成的insert和update语句
HIbernate在初始化阶段,根据文件的映射信息,为所有的持久化类预定义SQL语句(insert、update、delete、select)并将其保存在SessionFactory的内置缓存中。
当session执行相应的方法时(save、update、delete、load、get),直接从缓存中调用预定义的SQL并绑定参数。
通过设置动态SQL语句提高性能, 即在持久化类的映射文件中将class的属性 dynamic-update设置成true,则Hibernate可以根据Session中保存的Monkey快照,在update时只会包含需要更新的字段。
注意:
HIbernate有两种配置文件:hibernate.properties和hibernate.cfg.xml。HIbernate默认会到classpath路径下加载hibernate.properties文件。 如果该文件不存在,则通过Configuration的configure()显示加载hibernate.cfg.xml。
2.映射对象标识符OID
2.1 对象标识符(OID)
- java语言使用内存地址来识别和区分同一个类的不同对象;
- 关系数据库按主键值来识别和区分同一个表的不同记录;
- Hibernate使用对象标识符(OID)来建立Session缓存中的对象和数据库表中记录的一一对应关系(session中对象的OID和数据库表的主键一一对应)。
2.2 主键设置自动增长
常用数据库主键设置自动增长:Mysql采用 auto_increment;MS SQL Server采用 identify ;Oracel使用序列(Sequence)中获取自动增长的标识符。
最佳实践:将持久化类的OID的setId()方法设置成private类型以防止Java应用程序随便修改OID。而将getId()设置成public使得Java应用程序可以读取持久化对象的OID。
2.3 Hibernate的内置标识符生成器
持久化类的映射文件中<generator>子元素的calss属性用来设定标识符生成器。
Hibernate的常用标识符生成器:increment、identity、sequence、hilo、native等。- increment:由Hibernate以递增的方式为代理主键赋值。在单个应用服务器上可以有效工作,不适合集群环境。
- hilo:由HIbernate按照一种high/low算法来生成标识符。不依赖于底层的数据库系统。
- identity:由底层的数据库来负责生成标识符。要求数据库把主键定义为自动增长字段类型。
- sequence:由底层的数据库提供的序列来生成标识符。要求底层的数据库系统必须支持序列。
- native:依据底层的数据库对自动生成标识符的支持能力,选择用identity、sequence或hilo标识符生成器。它能自动判断底层数据库提供的生成标识符机制。
最佳实践:使用native标识符生成器,可以跨数据库平台。
2.4 补充说明
关系数据库中的主键可以分为自然主键(具有业务含义)和代理主键(不具有业务含义),代理主键更加流行,且通常为整数类型。与此对应,在持久化类中应把OID定义为整数类型,Hibernate把OID定义为long、int或short。
3.映射一对多关联关系
说明:一对多关联与多对一关联在本节中意义等价。
在关系数据库中,只存在外键参照关系,而且总是由“many”的一方参照“one”的一方。实际上关系数据库中只存在多对一或一对一的单向关联。假设存在如下图3-1所示的关系:
图3-1 MONKEYS表参照TEAMS表
3.1 建立多对一的单向关联关系
持久化类Monkey与Team是多对一的关系,在Monkey中有一个Team类型的team属性。
public class Monkey {
...
private Team team;
...
}
Monkey通过Monkey.hbm.xml映射MONKEYS表,其中:
- name映射NAME,类型相同String类型,使用<property>映射:
<property name="name" type="string" column="NAME" /> <!--type="string"为Hibernate的映射类型-->
- team(Team类型)映射TEAM_ID(整型),类型不匹配,使用<many-to-one>映射
<many-to-one
name="team" <!--持久化类Monkey中要映射的属性team-->
column="TEAM_ID" <!--同持久化类的属性对应的表的外键TEAM_ID-->
class="mypack.Team" <!--表明team属性的类型为mypack.Team->
cascade="save-update" <!--默认为none,设置级联保存和更新-->
lazy="false" <!--立即加载策略,默认为true-->
/>
说明:cascade的值设置成save-update,可以保证当Hibernate在持久化临时对象时会自动持久化其所关联的其他临时对象。也就是说,在保存或更新Monkey对象时,会自动保存或更新与之关联的Team对象。
3.2 映射一对多双向关联
前面3.1中已经建立了Monkey端的多对一单向关联,再加上本节Team端的一对多关联,就是双向关联了。
- 在Team中增加如下属性:
public class Team{
...
private Set monkeys = new HashSet();
...
}
最佳实践:在持久化类中声明接口类型的集合属性,并为他初始化为集合实现类的一个实例(可扩展、健壮性)。
- Team通过Team.hbm.xm与TEAMS映射,· 映射monkeys属性(TEAMS表中没有与其对应的字段),使用<set>
<set
name="monkeys" <!--持久化类Team中要映射的属性monkeys-->
inverse="true" <!--控制权交给Monkey-->
cascade="save-update" <!--默认为none,设置级联保存和更新-->
>
<key column="TEAM_ID" /> <!--表明关联Monkey对应的表MONKEYS的外键-->
<one-to-many class="mypack.Monkey" /> <!--表明monkeys集合中的对象为Monkey类型-->
</set>
最佳实践:在建立一对多的双向关联关系时,应该在“
one
”的一方把
<set>
元素的
inverse
属性设置为
true,可以提高应用的性能。在建立两个对象的双向关联时,同时修改关联两端的对象的相应属性。
- 再议cascade
delete—— 级联删除,删除一个持久化对象(如Team)时,会自动删除与之关联的持久化对象(Monkey