对于ORM而言,一个重要的特性就是对实体之间关联关系的管理。数据关联是ORM一个重要的特征,但往往也是导致性能低下的原因,在开发中要特别注意这一点。
一对一关联有两种类型:主键关联和唯一外键关联
一.主键关联:
一对一主键关联形式,即两张关联表通过主键形成一对一映射关系。
例如,一个中国公民只能有一份护照。
1.数据模型如下
2.表定义sql
DROP TABLE T_User;
DROP TABLE T_Passport;
CREATE TABLE T_Passport(
id INT NOT NULL
,serial VARCHAR ( 30 )
,expiry INT
, PRIMARY KEY (id)
);
CREATE TABLE T_User(
id INT NOT NULL AUTO_INCREMENT
,name VARCHAR ( 50 )
,age INT
, PRIMARY KEY (id)
, INDEX (id)
, CONSTRAINT FK_T_User_1 FOREIGN KEY (id)
REFERENCES T_Passport(id)
);
3.POJO类
TUser.java
packagecn.blogjava.start;
publicclassTUserimplementsjava.io.Serializable{
//Fields
privateIntegerid;
privateIntegerage;
privateStringname;
privateTPassportpassport;
//Constructors
publicIntegergetAge(){
returnage;
}
publicvoidsetAge(Integerage){
this.age=age;
}
publicTPassportgetPassport(){
returnpassport;
}
publicvoidsetPassport(TPassportpassport){
this.passport=passport;
}
/**defaultconstructor*/
publicTUser(){
}
/**constructorwithid*/
publicTUser(Integerid){
this.id=id;
}
//Propertyaccessors
publicIntegergetId(){
returnthis.id;
}
publicvoidsetId(Integerid){
this.id=id;
}
publicStringgetName(){
returnthis.name;
}
publicvoidsetName(Stringname){
this.name=name;
}
}
TPassport.java
packagecn.blogjava.start;
importjava.io.Serializable;
publicclassTPassportimplementsSerializable{
privateIntegerid;
privateStringserial;
privateIntegerexpiry;
privateTUseruser;
publicIntegergetExpiry(){
returnexpiry;
}
publicvoidsetExpiry(Integerexpiry){
this.expiry=expiry;
}
publicIntegergetId(){
returnid;
}
publicvoidsetId(Integerid){
this.id=id;
}
publicStringgetSerial(){
returnserial;
}
publicvoidsetSerial(Stringserial){
this.serial=serial;
}
publicTUsergetUser(){
returnuser;
}
publicvoidsetUser(TUseruser){
this.user=user;
}
}
3.配置文件
TUser.hbm.xml
<?xmlversion="1.0"?>
<!DOCTYPEhibernate-mappingPUBLIC"-//Hibernate/HibernateMappingDTD3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<classname="cn.blogjava.start.TUser"table="T_User"catalog="sample">
<idname="id"type="integer">
<columnname="id"/>
<generatorclass="native"/>
</id>
<propertyname="name"type="string">
<columnname="name"length="100"not-null="true"/>
</property>
<propertyname="age"type="java.lang.Integer"column="age"/>
<one-to-onename="passport"
class="cn.blogjava.start.TPassport"
cascade="all"
outer-join="true"
/>
</class>
</hibernate-mapping>
注意:outer-join="true"的设置,最后面的这样测试打印的结果:
Hibernate: select tuser3x0_.id as id18_1_, tuser3x0_.name as name18_1_, tuser3x0_.age as age18_1_, tpassport1_.id as id19_0_, tpassport1_.serial as serial19_0_, tpassport1_.expiry as expiry19_0_ from sample.t_user3 tuser3x0_ left outer join sample.t_passport tpassport1_ on tuser3x0_.id=tpassport1_.id where tuser3x0_.id=?
user name is byf
passport serial NO. is PCN123456
可以看到,当我们加载TUser实例时,Hibernate通过left outer join将t_user表及其关联的t_passpord完成读入。
如果我们将这里的节点的outer-join="false",那么Hibernate将执行下面的SQL语句执行:
Hibernate: select tuser3x0_.id as id10_, tuser3x0_.name as name10_, tuser3x0_.age as age10_ from sample.t_user3 tuser3x0_ where tuser3x0_.id=2
Hibernate: select tpassport0_.id as id11_0_, tpassport0_.serial as serial11_0_, tpassport0_.expiry as expiry11_0_ from sample.t_passport tpassport0_ where tpassport0_.id=?
user name is byf
passport serial NO. is PCN123456
设为outer-join="true",这本也是Hibernate提升性能减少数据库访问的一个优化措施。
但是当outer-join="true"时,你的lazy属性无论设置为任何值,Collection都会初始加载(
one-to-one没有lazy 因此不必考虑)请大家谨慎设置outer-join="true"
TPassport.hbm.xml
<?xmlversion="1.0"?>
<!DOCTYPEhibernate-mappingPUBLIC"-//Hibernate/HibernateMappingDTD3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<classname="cn.blogjava.start.TPassport"table="T_Passport"catalog="sample">
<idname="id"type="integer"column="id">
<generatorclass="foreign">
<paramname="property">user</param>
</generator>
</id>
<propertyname="serial"type="string"column="serial"/>
<propertyname="expiry"type="java.lang.Integer"column="expiry"/>
<one-to-onename="user"
class="cn.blogjava.start.TUser"
constrained="true"
/>
</class>
</hibernate-mapping>
4.测试代码
packagecn.blogjava.start;
importjava.util.List;
importjunit.framework.Assert;
importjunit.framework.TestCase;
importorg.hibernate.HibernateException;
importorg.hibernate.Session;
importorg.hibernate.SessionFactory;
importorg.hibernate.Transaction;
importorg.hibernate.cfg.Configuration;
publicclassHibernateTestextendsTestCase{
Sessionsession=null;
protectedvoidsetUp(){
try{
Configurationconfig=newConfiguration().configure();
SessionFactorysessionFactory=config.buildSessionFactory();
session=sessionFactory.openSession();
}catch(HibernateExceptione){
e.printStackTrace();
}
}
protectedvoidtearDown(){
try{
session.close();
}catch(HibernateExceptione){
e.printStackTrace();
}
}
publicvoidtestInsert(){
Transactiontran=null;
try{
TUseruser=newTUser();
user.setName("byf");
user.setAge(newInteger(26));
TPassportpassport=newTPassport();
passport.setSerial("PCN123456");
passport.setExpiry(newInteger(20081010));
//设置相互关联
user.setPassport(passport);
passport.setUser(user);
tran=session.beginTransaction();
session.save(user);
session.flush();
tran.commit();
Assert.assertEquals(user.getId().intValue()>0,true);
}catch(HibernateExceptione){
e.printStackTrace();
Assert.fail(e.getMessage());
if(tran!=null){
try{
tran.rollback();
}catch(Exceptione1){
e1.printStackTrace();
}
}
}
}
/**
* 对象读取测试(Select方法)
*/
public void testSelect2(){
try {
TUser user = (TUser)session.load(TUser.class, new Integer(3));
System.out.println("user name is " + user.getName());
System.out.println("passport serial NO. is " + user.getPassport().getSerial());
Assert.assertEquals(user.getName(), "byf");
} catch (Exception e) {
e.printStackTrace();
Assert.fail(e.getMessage());
}
}
}
分享到:
相关推荐
一、Hibernate一对一关联类型 一对一关联在现实世界中很常见,例如一个人只有一个身份证,一个身份证也只能属于一个人。在数据库设计中,这种关系通常通过主键和外键的方式实现,其中一方的主键作为另一方的外键,...
本篇将重点讲解如何实现一对一主键关联映射的单向关联,并通过一个实际的例子来帮助理解。 在一对一主键关联映射中,两个实体共享同一个主键,这意味着它们在数据库中的记录具有相同的标识符。这种映射关系通常用于...
首先,我们需要理解一对一关联关系的基本概念。在数据库中,一对一关系意味着两个表中的每一条记录都对应另一表中的唯一一条记录。在Hibernate中,这种关系可以通过共享主键或外键来实现。由于题目中提到的是“主键...
总之,理解并正确实现Hibernate中的一对一主键关联对于优化数据模型和提高代码的可维护性至关重要。通过共享主键,我们可以确保数据的完整性和一致性,同时简化对象之间的交互。阅读提供的博客资源,结合本文的讲解...
在Hibernate中,一对一关联可以通过`@OneToOne`注解来实现。这个注解可以放在属性上,表示该属性对应另一个实体的实例。外键通常设置在关系的“从属”一方,也就是依赖于其他实体的一方。 对于联合主键,我们需要...
通过以上分析,我们可以了解到Hibernate中一对一关联映射的原理和实现方法,以及如何进行双向一对一双向关联的配置。实际应用中,需要根据业务需求选择合适的映射方式,并注意维护好关联关系的正确性。在...
本篇文章将深入探讨两种实现一对一关联的方式:主键关联(Primary Key Join)和唯一外键关联(ForeignKey Join),并结合源码和实际工具进行详细讲解。 一、主键关联(Primary Key Join) 1. 主键关联的概念: ...
这篇博客文章“hibernate一对多关联映射(单向关联)”将深入讲解如何配置和使用这种映射关系。 在单向关联中,只有一个实体知道另一个实体的存在,也就是说,只有父实体("一"的一端)有对子实体("多"的一端)的...
值得注意的是,虽然共享主键的一对一关联在某些情况下简化了设计,但也有其缺点,如可能导致数据冗余和违反数据库规范化原则。因此,在实际应用中,需要根据业务需求权衡是否采用这种关联方式。 此外,对于源码和...
在上面的例子中,User和Profile都有对对方的引用,这被称为双向一对一关联。如果不希望在一方有引用,可以去掉`mappedBy`属性,变成单向一对一关联。 6. **外键策略**: Hibernate默认会在被引用的一方(在这里是...
本示例将深入讲解如何在Hibernate中实现主键一对一关联映射,并通过代码示例进行解析。 一对一关联意味着在一个实体中,每个实例都唯一对应另一个实体的实例。这种关联可以通过共享主键(primary key)或外键...
1. **一对一关联(One-to-One)**:一个实体对应数据库中的另一张表中的唯一一条记录。这可以通过在主键上添加外键约束或使用单独的关联表来实现。 2. **一对多关联(One-to-Many)**:一个实体可以与数据库表中的...
在保存或更新实体时,Hibernate会自动处理一对一关联的外键维护。 6. **懒加载与立即加载**:在一对一关系中,可以设置fetch属性来控制关联对象的加载策略,如懒加载(延迟加载)和立即加载。 7. **级联操作**:...
本教程通过源代码的形式,讲解如何在Hibernate中实现一对多主键关联映射,适用于初学者学习。 首先,我们需要理解一对多关联的基本概念。在数据库中,一个表的某一列(主键)可能与另一个表的多行相关联,比如一个...
`hibernate_course2.zip`可能是一个包含更多关于Hibernate教程的压缩包,里面可能有相关的代码示例、讲解文档或视频课程,可以帮助你更深入地理解和实践一对一外键关系。 总之,理解并熟练掌握Hibernate中的一对一...
总的来说,这个“hibernate one to one一对一关系示例”涵盖了如何在Hibernate中定义和操作一对一关联的基本步骤,包括实体类的注解配置、数据库表结构设计以及相关操作。通过对示例的深入学习,开发者能够更好地...
这里,Person和Address类共享同一主键`PERSON_ID`,表明它们一对一关联。 2. **单方外键关联(Unidirectional Foreign Key Join)** 在单方外键关联中,一个实体通过外键字段引用另一个实体。配置如下: ```xml ...
- 为避免数据冗余,考虑是否真的需要一对一关联,有时候合并成一个实体更合适。 - 优化懒加载,避免N+1查询问题,通过HQL或 Criteria API 进行批量加载。 - 注意级联操作可能导致数据的意外修改,使用时要谨慎。 ...
作者通过在博客中分享,详细讲解了如何在Java应用程序中使用Hibernate实现对象关系映射时的一对一关联,并可能涉及到实体类的设计、配置文件的编写以及相关的API使用。 **标签:“源码 工具”** **知识点详解:** ...
多对一关联是与一对一关联相对的概念,意味着多个实体可以关联到一个单一的实体。例如,多个学生可以属于同一个班级。在Java类中,这通常表现为一个实体类中包含另一个实体类的引用,并使用`@ManyToOne`注解进行标记...