跟我学Hibernate框架技术一对一的实体映射实现MySQL.docx
《跟我学Hibernate框架技术一对一的实体映射实现MySQL.docx》由会员分享,可在线阅读,更多相关《跟我学Hibernate框架技术一对一的实体映射实现MySQL.docx(24页珍藏版)》请在冰豆网上搜索。
![跟我学Hibernate框架技术一对一的实体映射实现MySQL.docx](https://file1.bdocx.com/fileroot1/2022-11/28/4f2c6c89-a407-4199-9c8c-97516cafde43/4f2c6c89-a407-4199-9c8c-97516cafde431.gif)
跟我学Hibernate框架技术一对一的实体映射实现MySQL
目录
1.1在Web应用中使用Hibernate技术----关联映射(MySQL)2
1.1.1一对一关联的实现方案2
1.1.2设计示例中的相关数据库表5
1.1.3采用JUnit单元测试实现25
1.1在Web应用中使用Hibernate技术----关联映射(MySQL)
1.1.1一对一关联的实现方案
1、一对一关联的实现方案
(1)一对一关联
(2)一对一关联在hibernate中有两种方式
●主键关联
不需借助外部字段,直接通过两个表的主键进行关联。
此时必须保证两个表的主键值一致(也就是id数据的值相等),在Hibernate中通常是借助foreign标识符生成器策略来完成。
简单来说,这种情况就是两个表的主键相等的内连接。
基于主键关联的单向一对一关联通常使用一个特定的id生成器foreign。
下面以“Address---》Person”的“一对一”的关联加以说明,其配置的方法。
person
createtablePerson(personIdbigintnotnullprimarykey)
createtableAddress(personIdbigintnotnullprimarykey)
注意:
在“主键关联”中使用“foreign”表示与外键共享主键,也就是与Person实体共享主键,而其中的“constrained”属性设定为true,则表示约束Address的主键必须与Person中对应数据的主键相同。
●
唯一外键关联
在主动方加入外键进行关联(如右图中,在Book表中增加一个PublishId字段),这样主动方与被动方的影射关系实际上就成了多对一的关联(请见后面的“多对一的关联”示例)。
基于外键关联的单向一对一关联和单向多对一关联几乎是一样的。
唯一的不同就是单向一对一关联中的外键字段具有唯一性约束。
createtablePerson(personIdbigintnotnullprimarykey,addressIdbigintnotnullunique)
createtableAddress(addressIdbigintnotnullprimarykey)
注意:
使用“唯一外键关联”来完成“一对一”的关联,其实就是限制“多对一”关系中,“多”的一方只能有一个参考至“一”的一方,也就是“多对一”关系的一个特例,这可以在映像文件中使用标签时,加上"unique"属性来设定。
2、主键关联的实现原理和要求
(1)要求
主键关联不需要额外的表字段;如果两行是通过这种一对一关系相关联的,那么这两行就共享同样的主关键字值。
所以如果你希望两个对象通过主键一对一关联,你必须确认它们被赋予同样的标识值!
(2)示例说明
比如说,对下面的Employee和Person进行主键一对一关联:
现在我们必须确保PERSON和EMPLOYEE中相关的字段是相等的。
(3)实现的原理
基于主键关联的单向一对一关联通常使用一个特定的id生成器foreign,我们使用一个被成为foreign的特殊的hibernate标识符生成策略。
employee
...
一个刚刚保存的Person实例被赋予和该Person的employee属性所指向的Employee实例同样的关键字值。
1.1.2设计示例中的相关数据库表
1、采用“主键关联”实现本例中的“一对一”实体之间的关联
(1)在MSSQLServer的本例的数据库中增加一个数据库表Publish
CREATEDATABASEDataBase;
USEDataBase;
droptablePublish;
CREATETABLEPublish
(
publish_idintNOTNULL,
publishNamenvarchar(20)NOTNULL,
publishAddressnvarchar(20)NOTNULL,
constraintpk_PublishPRIMARYKEY(publish_id)
);
insertPublishvalues(1,'xxx','yyyy');
insertPublishvalues(2,'xxx','yyyy');
(2)决定EBook和Publish之间的关系
显然,EBook是由某个出版社所出版,即EBook与Publish之间为“一对一”的关系。
其中的EBook类为主控方,而Publish类为被动方。
Onetoone
Publish
EBook
(3)新增一个Publish类,包名称为com.px1987.hexample.pobject
增加下面的各个属性定义,并提供get/set方法
privateIntegerid;
privateStringpublishName;
privateStringpublishAddress;
最后为下面的代码
packagecom.px1987.hexample.pobject;
publicclassPublish
{
privateIntegerid;
privateStringpublishName;
privateStringpublishAddress;
publicPublish(Integerid,StringnewPublishName,StringnewPublishAddress)
{
this.id=id;
this.publishName=newPublishName;
this.publishAddress=newPublishAddress;
}
publicPublish()
{
}
publicIntegergetId()
{
returnid;
}
publicvoidsetId(Integerid)
{
this.id=id;
}
publicStringgetPublishName()
{
returnthis.publishName;
}
publicvoidsetPublishName(StringnewPublishName)
{
this.publishName=newPublishName;
}
publicStringgetPublishAddress()
{
returnthis.publishAddress;
}
publicvoidsetPublishAddress(StringnewPublishAddress)
{
this.publishAddress=newPublishAddress;
}
@Override
publicinthashCode(){
finalintPRIME=31;
intresult=1;
result=PRIME*result+((id==null)?
0:
id.hashCode());
result=PRIME*result+((publishAddress==null)?
0:
publishAddress.hashCode());
result=PRIME*result+((publishName==null)?
0:
publishName.hashCode());
returnresult;
}
@Override
publicbooleanequals(Objectobj){
if(this==obj)
returntrue;
if(obj==null)
returnfalse;
if(getClass()!
=obj.getClass())
returnfalse;
finalPublishother=(Publish)obj;
if(id==null){
if(other.id!
=null)
returnfalse;
}elseif(!
id.equals(other.id))
returnfalse;
if(publishAddress==null){
if(other.publishAddress!
=null)
returnfalse;
}elseif(!
publishAddress.equals(other.publishAddress))
returnfalse;
if(publishName==null){
if(other.publishName!
=null)
returnfalse;
}elseif(!
publishName.equals(other.publishName))
returnfalse;
returntrue;
}
}
2、为该实体类创建一个Publish.hbm.xml映射文件
(1)新建Publish.hbm.xml映射文件
(2)该Publish.hbm.xml映射文件的内容如下
xmlversion="1.0"?
>
DOCTYPEhibernate-mapping
PUBLIC"-//Hibernate/HibernateMappingDTD3.0//EN"
"
注意:
同时由于Publish表中的publish_id的产生方式设置为“increment”,因此应该在该数据库表中首先有数据(如可以给出下面的示例数据)。
否则将从1开始产生!
(3)在hibernate.cfg.xml配置文件中增加对该文件的定义
xmlversion='1.0'encoding='utf-8'?
>
DOCTYPEhibernate-configurationPUBLIC"-//Hibernate/HibernateConfigurationDTD//EN"
"
java:
comp/env/jdbc/datasource
false
org.hibernate.dialect.SQLServerDialect
--Mappingfiles-->
3、执行TestHibernateXML一识别*.xml文件的正确性
4、实现Ebook与Publish之间的“一对一”的关联
(1)修改Ebook.java类增加一个Publish类型的成员属性
packagecom.px1987.hexample.pobject;
importjava.util.*;
publicclassEBook
{
privateIntegerid;
privateStringebookName;
privatecharebookKind;
privatefloatebookPrice;
privatePublishpublish=null;
publicPublishgetPublish()
{
returnthis.publish;
}
publicvoidsetPublish(PublishnewPublish)
{
this.publish=newPublish;
}
publicEBook()
{
}
。
。
。
//其它代码不变
}
(2)在EBook.hbm.xml里面映射这个关联-------“one-to-one”关系定义规则
“one-to-one”关系定义比较简单,只需在主控方加以定义(本例为EBook类)。
这里,我们的目标是由EBook对象获取其对应的Publish对象。
因此EBook对象是主控方,为了实现“一对一”关系,我们在EBook对象的映射文件EBook.hbm.xml中加入标签节点,对Publish对象进行一对一关联。
(3)修改EBook.hbm.xml文件以增加下面的内容
xmlversion="1.0"?
>
DOCTYPEhibernate-mapping
PUBLIC"-//Hibernate/HibernateMappingDTD3.0//EN"
"
publish
注意:
其中的cascade="none",表示不需要进行级连。
(3)标签的说明
参考hibernate的官方指导手册,下面给出标签的说明
name="propertyName"
(1)
class="ClassName"
(2)
cascade="all|none|save-update|delete"(3)
constrained="true|false"(4)
outer-join="true|false|auto"(5)
property-ref="propertyNameFromAssociatedClass"(6)
access="field|property|ClassName"(7)
/>
其中的各个属性的说明如下:
(1)name:
映射属性的名称。
(2)class(可选):
被关联的类的名称,如果省略此属性,则通过反射机制得到与此属性名称一致的类。
(3)cascade(可选)表明操作是否从父对象级联到被关联的对象。
(4)constrained(可选):
表明该类对应的表对应的数据库表,和被关联的对象所对应的数据库表之间,通过一个外键引用对主键进行约束。
这个选项影响save()和delete()在级联执行时的先后顺序。
(5)outer-join(可选):
是否允许外连接抓取;默认是auto,关联对象没有采用proxy机制时使用外联接。
(6)property-ref(可选):
指定关联类的一个属性,这个属性将会和本外键相对应。
默认为关联类的主键。
(7)access(可选):
Hibernate用来访问属性的策略,默认是property.
5、对cascade级联属性的说明
(1)作用
Hibernate允许我们为每个关系映射指定级联形式,为所有的状态转换提供更复杂更精确的控制。
Hibernate读取声明的状态并自动级联操作到相关的对象------当主控方执行操作时,关联对象(被动方)是否同步执行同一操作。
因为当Hibernate持久化一个临时对象时,在默认情下,他不会自动持久化所关联的其他临时对象,如果希望当持久化对象时把他所关联的所有临时对象进行持久化的话:
可以设置cascade属性。
(2)注意的问题
●cascade的默认值为false
●只有“关系标签”才有cascade属性:
many-to-one,one-to-one,any,set(map,bag,idbag,list,array),one-to-many(many-to-many)。
(3)一个操作因级联cascade可能触发多个关联操作
我们把前一个操作叫“主控操作”,而把后一个操作叫“关联操作”。
cascade属性的可选值:
●All:
所有情况下均进行关联操作。
●none:
所有情况下均不进行关联操作。
这是默认值。
●save-update:
在执行save/update/saveOrUpdate时进行关联操作。
●delete:
在执行delete时进行关联操作。
具体执行什么“关联操作”是根据“主控操作”来决定的:
“主控操作”“关联操作”
session.saveOrUpdate-->session.saveOrUpdate(执行saveOrUpdate实际上会执行save或者update)
session.save---->session.saveOrUpdate
session.udpate-->session.saveOrUpdate
session.delete-->session.delete
(4)为什么要提供级联操作---实现Hibernate的级联持久化
级联持久化的特性能够保证相互关联的数据之间的完整性约束,并且级联在编程中经常接触,当主控表信息改变时,用来保证其关联表中数据同步更新。
比如一个employee存放职员信息,一个timecard存放职员的考勤信息,当从职员表中删除一个职员时,timecard表中对应的考勤信息已经没有意义,因为其所属的职员已不存在,如果继续留在timecard表中就成了没用的也称脏数据。
理想的做法是在删除职员信息的同时将该职员信息对应的考勤信息也删除。
在hibernate中如果要达到这个效果只需要设置cascade属性值即可。
当然是否进行级联关系要根据实际情况慎重考虑。
(5)各种设置的值的含义
cascade属性设置为除了none(为从来不作级联操作)以外任何有意义的值,它将把特定的操作传播到关联对象中,这个值就代