一、主键生成策略及其配置

[b]1.increment[/b]生成器由Hibernate以递增的方式生成主键值,它的原理是先查询目标表最大的主键值+1,作为新增记录的主键值。 

increment是最简单的生成策略,但在高并发环境下可能会出现主键冲突! 

increment不推荐在项目中使用 

[b]2.identity[/b]标示符生成器由底层数据库来负责生成主键值,它要求底层数据库将主键定义为自动增长字段类型,如MySQL中将主键定义为auto_increment类型;在MS SQL Server中,应当把主键定义为identity类型。 

Oracle没有自增类型,所以不能使用identity策略 

在teacher.hbm.xml中配置例子: 

<hibernate-mapping package="com.bjsxt.score.entity"> 

<class name="Teacher" table="teacher"> 

 <id name="tno"> 

 <column name="tno"></column> 

 <generator class="native"> 

 </id> 

 <property name="tname" column="tname"></property> 

</class> 

</hibernate-mapping> 

[b]3.sequence[/b]标示符生成器利用底层数据库提供的序列来生成主键值。这是oracle中最经常使用的生成策略 

在teacher.hbm.xml中配置例子: 

<id name="tno" type="java.lang.Integer"> 

 <column name="tno"></column> 

 <generator class="sequence"> 

 <param name="sequence">seq_teacher</param> 

 </generator> 

</id> 

[b]4>hilo[/b]策略生成器由hibernate按照一种high/low算法生成主键值,他从数据库特定表的字段中获取high值。 

在teacher.hbm.xml中配置例子: 

首先需要在数据库中创建一个表,譬如表名称为hilo_value,表中设置一个字段,譬如字段next_value 

<id name="tno" type="java.lang.Integer"> 

 <column name="tno"></column> 

 <generator class="hilo"> 

 <param name="table">hilo_value</param> 

 <param name="column">next_value</param> 

 </generator> 

</id> 

[b]5.native[/b]会依据底层数据库自动选择适合的生成策略。 

如果数据库支持identity,则使用identity 

如果数据库支持sequence , 则使用sequence 

如果上述两者都不支持,则使用hilo 

配置例子: 

<id name="tno" type="java.lang.Integer"> 

 <column name="tno"></column> 

 <generator class="native"> 

 <param name="sequence">seq_teacher</param> 

 <param name="table">hilo_value</param> 

 <param name="column">next_value</param> 

 </generator> 

</id> 

[b]6.assigned[/b]是指不依赖Hibernate的任何主键生成策略,由程序手动指定记录的主键值。 

在teacher.hbm.xml中不用做任何配置。 

[b]7.UUID[/b]:Universally Unique Identifier,是指在一台机子上生成的数字,它保证在同一时空中的所有机器都是唯一的。按照开放软件基金会(OSF)制定的标准计算,用到了以太网卡地址、纳秒级时间、芯片ID码和许多可能的数字。 


[b]GUID:[/b]Globally Unique Identifier全球唯一标识符,是一个128位长的数字,用16位进制表示。算法的核心思想是结合网卡、当地时间、一个随机数来生成GUID。从理论上讲,如果一个机器每秒产生100000000个GUID,则可保证3240年不重复。 

写上<generator class="guid"></generator> 

[b]8.自然主键[/b]是具有含义的主键。如果从头设计数据表,应该避免使用自然主键,而尽量使用不具有业务含义的代理主键。 

自然主键一般是指:身份证、银行卡号、学生证号等等现实中存在的唯一标识。 

代理主键一般就是指与业务无关的序列号、GUID、UUID字符串等。 

[color=red]在设计数据库时推荐使用代理主键[/color]。因为在一个数据库中核心业务数据是不允许被删除的,而是使用一个标志该记录是否有效的字段,如果使用自然主键,当一条记录被标志位无效时后如果系统还要增加这条记录则会造成主键冲突。 

[color=red]二.表的关联[/color] 

[color=red]1.1对N关联[/color]使我们工作中使用最多的连接方式,在Hibernate中为我们提供了便捷的1对N配置。我们以教师授课为例。 

第一步:在“多”的Course一方,我们将Course的实体类中外键属性修改为对应的对象 

例子:[color=blue]Course实体类[/color] 

 修改前:private int tno;//教师编号 

 修改后:private Teacher teacher; //修改为教师对象 

[color=blue]在course.hbm.xml中增加<many-to-one>标签,说明要关联哪张主表[/color] 

//many-to-one 应写在“多”的一方 

//name 属性指明要映射那个属性, column是 course表的外键列 

// class是指要关联的哪个主表,hibernate中类既是表,表既是类 

[color=blue]<many-to-one name="teacher" column="tno" class="Teacher" ></many-to-one>[/color] 

第二步:在1的一方,通过List持有多个关联对象。例如:一个教室可以教授多门课程。 

在“1”的一方,我们增加List来保存多个关联对象。 

例子:Teacher实体类 

 [color=blue]private List courses; //多个课程对象[/color] 

 在teacher.hbm.xml中增加<bag>标签,说明这是通过哪个外键关联获取多个课程 

//bag标签说明适用List保存多个关联对象 

//inverse代表将关系的控制权,这里固定设置true. 

[color=red]<bag name=“courses” inverse=“true”>[/color] 

 //key 代表在关联表中的外键是哪个 

 //这里就是指course表的tno 

 [color=red]<key column=“tno”></key>[/color] 

 //one-to-many代表关联哪张从表,Hibernate中表既是类,类即是表 

[color=red] <one-to-many class="Course"/> 

</bag>[/color] 

[color=red]2.在关系型数据库中,多对多关[/color]联通常我们会增加一张中间表,将两张业务表与一张中间表做1对多关联即可。 

我们已学生、课程与成绩这个最简单的多对多关系,一个学生需要参加多门课程的考试,而一门课可以至少有一个学生参加考试。双向一对多就形成了多对多关系,我们就可以通过增加“成绩”这张中间表来描述多对多关系。 

成绩表结构如下: 

学号、课程号、成绩 

通过hibernate实现多对多的思路就是将“成绩表”作为中间表,与“课程”、“学生”表做双向一对多关联即可。 

例子:学生表与课程表:一个学生可以学多门课,一门课可以有多个学生来学,那么我们增加一个中间表StudentCourse,在这个表中只需要三个字段,一个主键scid,sno,cno 

[color=red]3.一对一关联[/color]在我们生活中很常见,人和身份证,孩子与生父、生母,你和档案。 

一对一关联的主要特征是,从表中的Id既是主键、也是外键。 

例如: 

教师表 Teacher(主表) 

tno –教师编号 , 主键 

tname – 教师姓名 

... 

教师档案表 TeacherInfomation(从表) 

tno – 教师编号,主键、外键 

address – 家庭地址... 

对于1对1关联我们可以是用<one-to-one>完成 

增加从表实体: 

Teacher类 

private TeacherInfomation ti; 

teacher.hbm.xml 

//one-to-one会自动分析并关联TeacherInfomation从表 

[color=red]<one-to-one name=“ti” ></one-to-one>[/color] 

TeacherInformation类 

增加主表实体:private Teacher teacher; 

//one-to-one会自动分析并关联Teacher主表 

[color=red]<one-to-one name="teacher" ></one-to-one>[/color] 

[color=red]测试1对1关联时要注意的问题:[/color]当两个表中的数据不是一一对应,即TeacherInformation表的信息不完全,在t.getTi是会发生空指针异常 

解决办法如下: 

public void testGetInfo(){ 

 Session session = DBUtils.getSession(); 

 List<Teacher> list = session.createQuery("from Teacher").list(); 

 for(Teacher t : list){ 

 if(t.getTi() != null){ 

 System.out.println(t.getTname() + " :" + t.getTi().getFather() + ":" + t.getTi().getMother()); 

 }else{ 

 System.out.println(t.getTname() ); 

 } 


 } 

 } 

[color=red]三:延迟加载-lazy属性[/color] 

Hibernate 的延迟加载(lazy load)是一个被广泛使用的技术。这种延迟加载保证了应用只有在需要时才去数据库中抓取相应的记录。通过延迟加载技术可以避免过多、过早地加载数据表里的数据,从而降低应用的内存开销。当程序通过 Hibernate 装载一个实体时,默认情况下,Hibernate 并不会立即抓取它的集合属性、关联实体所以对应的记录。只要需要用到的时候才回去抓取。 

当设置lazy=false是代表实体对象实例化时立即去抓取关联表数据 

<bag name="scores" inverse="true" lazy="false"> 

 <key column="cno"></key> 

 <one-to-many class="Score"/> 

</bag> 

[color=red]四:Cascade属性[/color] 

Cascade是指关联操作,它有以下四个值 

none – 默认值,不进行关联操作 

save-update – 进行保存及更新是关联操作,例如更该主表主键值,从表外键一并更新。 

delete-删主表数据,从表数据也一并被删除 

all 所有情况下都进行关联操作 


[color=red]<bag name="scores" inverse="true" cascade="delete" lazy="false">[/color] 

<key column="cno"></key> 

<one-to-many class="Score"/> 

</bag>