概述:

hibernate提供了两种映射一对一关联的方式:按照外键映射和按照主键映射。

下面以员工账号和员工档案为例 ,介绍两种映射方式,并使用这两种映射方式分别完成以下持久化操作:

(1)保存员工档案的同时分配给员工一个账号

(2)加载员工档案的同时加载账号信息

1.按照外键映射

第一步:创建实体类users1(主表)和resume1

package cn.lex.entity;

/**
* Created by accp on 2017/1/18.
* 员工表
*/
public class Users1 {
private Integer userid; //员工编号
private String username; //名称
private String userpass; //密码
private Resume1 resume1; //档案对象 public Integer getUserid() {
return userid;
} public void setUserid(Integer userid) {
this.userid = userid;
} public String getUsername() {
return username;
} public void setUsername(String username) {
this.username = username;
} public String getUserpass() {
return userpass;
} public void setUserpass(String userpass) {
this.userpass = userpass;
} public Resume1 getResume1() {
return resume1;
} public void setResume1(Resume1 resume1) {
this.resume1 = resume1;
}
}
package cn.lex.entity;

/**
* Created by accp on 2017/1/18.
* 档案表
*/
public class Resume1 { private Integer resid; // 档案编号
private String resname; //档案名称
private String rescardno; //编号
private Users1 users1; //隶属的员工 public Integer getResid() {
return resid;
} public void setResid(Integer resid) {
this.resid = resid;
} public String getResname() {
return resname;
} public void setResname(String resname) {
this.resname = resname;
} public String getRescardno() {
return rescardno;
} public void setRescardno(String rescardno) {
this.rescardno = rescardno;
} public Users1 getUsers1() {
return users1;
} public void setUsers1(Users1 users1) {
this.users1 = users1;
}
}

第二步:书写配置文件

Users1.hbm.xml:

<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="cn.lex.entity">
<class name="Users1" table="USERS1">
<id name="userid"><generator class="native"></generator></id>
<property name="username" column="USERNAME" type="string"></property>
<property name="userpass" column="USERPASS" type="string"></property>
<!-- 配置一对一外键方式的关联
property-ref:通过Resume1的users1属性,建立了从users1到Resume1对象的关联
-->
<one-to-one name="resume1" class="Resume1" property-ref="users1"></one-to-one>
</class>
</hibernate-mapping>

Resume1.hbm.xml:

<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="cn.lex.entity">
<class name="Resume1" table="RESUME1">
<id name="resid"><generator class="native"></generator></id>
<property name="resname" column="RESNAME" type="string"></property>
<property name="rescardno" column="RESCARDNO" type="string"></property>
<!-- column 与之关联表的外键 unique 可以表达Resume1对象和Users1对象之间的一对一关联关系
 unique属性的默认值为false 在这里要设为true才有效
-->
<many-to-one name="users1" class="Users1" cascade="all" unique="true" column="RESUSERID"></many-to-one>
</class>
</hibernate-mapping>

第三步:书写测试类

工具类:

package cn.lex.util;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration; /**
* Created by accp on 2017/1/16.
*/
public class HibernateUtil {
private static final ThreadLocal<Session> thLocal=new ThreadLocal<Session>();
private static Configuration cfg;
private final static SessionFactory factory;
static{
cfg=new Configuration().configure();
factory=cfg.buildSessionFactory();
}
/**
*静态的方法 返回session
*/
public static Session currentSession(){
Session session = thLocal.get();
if(session==null){
session=factory.openSession();
thLocal.set(session);
}
return session; } /**
* 静态的方法 关闭session连接
*/
public static void closeSession(){
Session session = thLocal.get();
if(session!=null){
thLocal.set(null);
}
session.close();
}
}

测试类:

    @Test

    /**
* 插入数据
*/
public void add(){
Session session = HibernateUtil.currentSession();
Transaction tx = session.beginTransaction();
//创建用户
Users1 users1=new Users1();
users1.setUsername("微冷的雨");
users1.setUserpass("");
//创建档案
Resume1 resume1=new Resume1();
resume1.setResname("入职档案");
resume1.setRescardno("");
//关联
users1.setResume1(resume1);
resume1.setUsers1(users1); session.save(resume1);
tx.commit();
HibernateUtil.closeSession();
}

SQL语句:

Hibernate:
drop sequence hibernate_sequence
Hibernate:
create sequence hibernate_sequence start with 1 increment by 1
Hibernate:
create table RESUME1 (
resid number(10,0) not null,
RESNAME varchar2(255 char),
RESCARDNO varchar2(255 char),
RESUSERID number(10,0),
primary key (resid)
)
Hibernate:
create table USERS1 (
userid number(10,0) not null,
USERNAME varchar2(255 char),
USERPASS varchar2(255 char),
primary key (userid)
)
Hibernate:
alter table RESUME1
add constraint UK_j52v359nm8h98x9dmuvbka6tb unique (RESUSERID)
Hibernate:
alter table RESUME1
add constraint FKhp8mabk7imse3kohw5lul5k29
foreign key (RESUSERID)
references USERS1
Hibernate:
select
hibernate_sequence.nextval
from
dual
Hibernate:
select
hibernate_sequence.nextval
from
dual
Hibernate:
insert
into
USERS1
(USERNAME, USERPASS, userid)
values
(?, ?, ?)
Hibernate:
insert
into
RESUME1
(RESNAME, RESCARDNO, RESUSERID, resid)
values
(?, ?, ?, ?)

结果:

看到这里是不是觉得跟前面学的多对一关联映射没什么不同?开始的时候我也是这种心态,但是你接下来看就会知道了,我们来做一个查询操作。

模拟一下场景,你是不是很不理解uses1.hbm.xml中<one-to-one>中为什么要加上property-ref,它到底是干什么的呢?

接下来我们先把它去掉,看看效果。

Users1.hbm.xml:

测试结果:

接下来我们看看当我们加上property-ref属性的时候得到的结果:

  这样是不是很直观的就可以看出两个结果的不同,那么我们得到什么结论呢?

当我们做一对一映射时,在主键表的配置中,一定要书写property-ref属性,否则当你查询数据时,底层生成SQL时,会主动把两个表的主键id关联,从而得到错误的结果。

2.按照主键映射

第一步:实体类Users2(从表)和Resume2(主表)

package cn.lex.entity;

/**
* Created by accp on 2017/1/18.
* 员工表 从表
*/
public class Users2 {
private Integer userid;
private String username;
private String userpass;
private Resume2 resume2; public Integer getUserid() {
return userid;
} public void setUserid(Integer userid) {
this.userid = userid;
} public String getUsername() {
return username;
} public void setUsername(String username) {
this.username = username;
} public String getUserpass() {
return userpass;
} public void setUserpass(String userpass) {
this.userpass = userpass;
} public Resume2 getResume2() {
return resume2;
} public void setResume2(Resume2 resume2) {
this.resume2 = resume2;
}
}
package cn.lex.entity;

/**
* Created by accp on 2017/1/18.
* 档案表 主表
*/
public class Resume2 {
private Integer resid;
private String resname;
private String rescardno;
private Users2 users2; public Integer getResid() {
return resid;
} public void setResid(Integer resid) {
this.resid = resid;
} public String getResname() {
return resname;
} public void setResname(String resname) {
this.resname = resname;
} public String getRescardno() {
return rescardno;
} public void setRescardno(String rescardno) {
this.rescardno = rescardno;
} public Users2 getUsers2() {
return users2;
} public void setUsers2(Users2 users2) {
this.users2 = users2;
}
}

第二步:配置文件Users2.hbm.xml和Resume2.hbmxml

Resume2.hbmxml:

<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="cn.lex.entity">
<class name="Resume2" table="RESUME2">
<id name="resid">
<!-- 主键生成策略-->
<generator class="native">
</generator></id>
<property name="resname" column="RESNAME" type="string"></property>
<property name="rescardno" column="RESCARDNO" type="string"></property>
<one-to-one name="users2" class="Users2" cascade="all"></one-to-one>
</class>
</hibernate-mapping>

Users2.hbm.xml:

<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="cn.lex.entity">
<class name="Users2" table="USERS2">
<id name="userid">
<!-- 使用foreign 主键生成策略额,hibernate就会保证Users2对象与Resume2对象共享同一个OID-->
<generator class="foreign">
<param name="property">resume2</param>
</generator>
</id>
<property name="username" column="USERNAME" type="string"></property>
<property name="userpass" column="USERPASS" type="string"></property>
<!-- <one-to-one>元素的constrained属性为true ,表明Users2表的USERID主键同时作为外键参照RESUME2表的主键
-->
<one-to-one name="resume2" class="Resume2" constrained="true"></one-to-one>
</class>
</hibernate-mapping>

第三步:书写测试类

  @Test
public void add1(){
Session session = HibernateUtil.currentSession();
Transaction tx = session.beginTransaction();
//创建用户
Users2 users2=new Users2();
users2.setUsername("帅的离谱");
users2.setUserpass("");
//创建档案
Resume2 resume2=new Resume2();
resume2.setResname("离职档案");
resume2.setRescardno("");
//关联
users2.setResume2(resume2);
resume2.setUsers2(users2); session.save(resume2);
tx.commit();
HibernateUtil.closeSession();
}

SQL语句:

Hibernate:
create table RESUME2 (
resid number(,) not null,
RESNAME varchar2( char),
RESCARDNO varchar2( char),
primary key (resid)
)
Hibernate:
create table USERS2 (
userid number(,) not null,
USERNAME varchar2( char),
USERPASS varchar2( char),
primary key (userid)
)
Hibernate:
alter table USERS2
add constraint FKbhwvd9exxeaymfiyjkgdqgtcp
foreign key (userid)
references RESUME2
Hibernate:
select
hibernate_sequence.nextval
from
dual
Hibernate:
insert
into
RESUME2
(RESNAME, RESCARDNO, resid)
values
(?, ?, ?)
Hibernate:
insert
into
USERS2
(USERNAME, USERPASS, userid)
values
(?, ?, ?)

数据库体现:

结论:USERS2表的USERID字段是主键,同时作为外键参照RESUME2表的主键,即USERS2表与RESUME2表共享主键。

接下来我们写一个查询测试代码,看一下有什么不同?

测试代码:

  @Test
public void select1(){
Session session = HibernateUtil.currentSession();
Transaction tx = session.beginTransaction();
Users2 users2 = session.load(Users2.class, );
System.out.println(users2.getResume2().getResname());
tx.commit();
HibernateUtil.closeSession();
}

SQL:

以上是Hibernate提供的两种一对一关联映射的方式,在实际的开发中,按照数据库表的设计选择相应的映射方式,当两个类之间只有一对一的关联时,应该优先考虑使用主键映射方式。

3.组件映射

建立关系数据模型的一个重要原则是在不会导致数据冗余的前提下,尽可能减少数据库表的数目及表之间的外键参照关系。以员工信息为例,员工信息中有员工的家庭地址信息,如果把地址信息单独放在一张表中,然后建立员工信息表和地址信息表之间的外键参照关系,当每次查询员工信息时,都需建立者两个表的连接。建立表的连接是很耗时的操作,为了提高数据库运行性能,可以把这两张表的信息整合在一张员工信息表EMPINFO中。

第一步:创建EmpInfo类和EmpHomeAddress类

EmpInfo表:

package cn.lex.entity;

/**
* Created by accp on 2017/1/18.
* 员工信息表
*/
public class EmpInfo {
private Integer eid;
private String ename;
private EmpHomeAddress ehome; public Integer getEid() {
return eid;
} public void setEid(Integer eid) {
this.eid = eid;
} public String getEname() {
return ename;
} public void setEname(String ename) {
this.ename = ename;
} public EmpHomeAddress getEhome() {
return ehome;
} public void setEhome(EmpHomeAddress ehome) {
this.ehome = ehome;
}
}

EmpHomeAddress表:

package cn.lex.entity;

/**
* Created by accp on 2017/1/18.
* 员工地址表
*/
public class EmpHomeAddress {
private String ehomestreet;
private String ehomecity;
private String ehomeprovince;
private String ehomezipcode;
private EmpInfo empinfo; public String getEhomestreet() {
return ehomestreet;
} public void setEhomestreet(String ehomestreet) {
this.ehomestreet = ehomestreet;
} public String getEhomecity() {
return ehomecity;
} public void setEhomecity(String ehomecity) {
this.ehomecity = ehomecity;
} public String getEhomeprovince() {
return ehomeprovince;
} public void setEhomeprovince(String ehomeprovince) {
this.ehomeprovince = ehomeprovince;
} public String getEhomezipcode() {
return ehomezipcode;
} public void setEhomezipcode(String ehomezipcode) {
this.ehomezipcode = ehomezipcode;
} public EmpInfo getEmpinfo() {
return empinfo;
} public void setEmpinfo(EmpInfo empinfo) {
this.empinfo = empinfo;
}
}

第二步:创建EmpInfo.hbm.xml配置文件

EmpInfo.hbm.xml:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="cn.lex.entity">
<class name="EmpInfo" table="EMPINFO">
<id name="eid" column="EID">
<generator class="native"></generator>
</id>
<property name="ename" column="ENAME" type="string"></property>
<component name="ehome" class="EmpHomeAddress">
<parent name="empinfo"/>
<property name="ehomestreet" column="EHOMESTREET" type="string"></property>
<property name="ehomecity" column="EHOMECITY" type="string"></property>
<property name="ehomeprovince" column="EHOMEPROVINCE" type="string"></property>
<property name="ehomezipcode" column="EHOMEZIPCODE" type="string"></property>
</component>
</class>
</hibernate-mapping>

<component>元素:表明ehome属性是EmpInfo类的一个组成部分,在Hibernate中称为组件。

<component>元素有两个属性:

(1)name:设定被映射的持久化类的属性名,此处为EmpInfo类的ehome属性。

(2)class:设定ehome属性的类型,此处表明ehome属性为EmpHomeAddress类型。

<componet>元素还包含一个<parent>子元素和一系列<property>子元素。<parent>元素指定EmpHomeAddress类所属的整体类,在这里设为empinfo。

第三步:书写测试类:

 /**
* 插入数据 组件映射
*/
@Test
public void add2() {
Session session = HibernateUtil.currentSession();
Transaction tx = session.beginTransaction();
//创建一个员工对象
EmpInfo emp = new EmpInfo();
emp.setEname("张靓颖"); //创建一个员工地址对象
EmpHomeAddress address = new EmpHomeAddress();
address.setEhomecity("海淀区");
address.setEhomeprovince("北京");
address.setEhomestreet("五道口");
address.setEhomezipcode("");
address.setEmpinfo(emp);
emp.setEhome(address);
session.save(emp);
tx.commit();
HibernateUtil.closeSession();
}

SQL :

数据库数据:

在这里是没有EmpHomeAddress类的映射文件,数据库也不会创建表。

查询语句:

 @Test
public void select2() {
Session session = HibernateUtil.currentSession();
Transaction tx = session.beginTransaction();
EmpInfo empInfo = session.load(EmpInfo.class, );
System.out.println("姓名:" + empInfo.getEname());
System.out.print("地址:" + empInfo.getEhome().getEhomeprovince() + empInfo.getEhome().getEhomecity() + empInfo.getEhome().getEhomestreet());
tx.commit();
HibernateUtil.closeSession();
}

SQL语句:

上面以EmpInfo和EmpHomeAddress类为例介绍了组件映射,Hibernate用<componet>元素来映射EmpInfo类的ehome属性。

EmpHomeAddress类作为Hibernate的组件,具有以下特征:

(1)EmpHomeAddress类没有OID,在数据库中也没有与之对应的表,不需要单独创建EmpHomeAddress类的映射文件。

(2)不能单独持久化EmpHomeAddress对象。EmpHomeAddress对象的生命周期依赖于EmpInfo对象的生命周期。

(3)其他持久化类不允许关联EmpHomeAddress类,EmpHomeAddress可以关联其他持久化类。

Hibernate 性能优化一对一关联映射的更多相关文章

  1. 【Hibernate框架】关联映射(一对一关联映射)

    一.整理思路: 之前,小编总结过Mybatis的关联映射,接下来,再来总结一下hibernate的相关的关联映射,直接上图: 这张图,就是小编整理总结整个Hibernate的关联映射的一个大致思路. ...

  2. Hibernate学习笔记(四)关系映射之一对一关联映射

    一. 一对一关联映射 ²        两个对象之间是一对一的关系,如Person-IdCard(人—身份证号) ²        有两种策略可以实现一对一的关联映射 Ø        主键关联:即让 ...

  3. 【学习笔记】Hibernate 一对一关联映射 组件映射 二级缓存 集合缓存

    啊讲道理放假这十天不到啊 感觉生活中充满了绝望 这就又开学了 好吧好吧继续学习笔记?还是什么的 一对一关联映射 这次我们仍然准备了两个表 一个是用户表Users 一个是档案表Resume 他们的关系是 ...

  4. Hibernate 一对一关联映射,mappedBy参数解析

    在最近java,SSH框架的学习中遇到了这样的一个问题,在Hibernate的开发中一对一关联映射的单向关联,主表会在次表新增一列次表的主键如下图,但是在双向关联中次表不会在表中创建主表的主键一列,这 ...

  5. Hibernate之一对一关联映射

    Hibernate中一对一关联映射共分为两种,一种是一对一主键关联映射,另一种是一对一唯一外键关联映射.下面简单介绍一下这两种关联映射. 一对一主键关联映射 一对一主键关联映射的两个实体有相同的ID. ...

  6. java之hibernate之基于主键的双向一对一关联映射

    这篇 基于主键的双向一对一关联映射 1.依然考察人和身份证的一对一关系,如果采用主键关联,那么其表结构为: 2.类结构 Person.java public class Person implemen ...

  7. java之hibernate之基于主键的单向一对一关联映射

    这篇讲 基于主键的单向一对一关联映射 1.依然考察人和身份证的一对一关系,如果采用主键关联,那么其表结构应该为: 2.类结构 Person.java public class Person imple ...

  8. java之hibernate之基于外键的双向一对一关联映射

    这篇讲解 基于外键的双向一对一关联映射 1.考察如下信息,人和身份证之间是一个一对一的关系.表的设计 2.类结构 Person.java public class Person implements ...

  9. Hibernate性能优化之EHCache缓存

    像Hibernate这种ORM框架,相较于JDBC操作,需要有更复杂的机制来实现映射.对象状态管理等,因此在性能和效率上有一定的损耗. 在保证避免映射产生低效的SQL操作外,缓存是提升Hibernat ...

随机推荐

  1. 关于前后台DOM树应用

    Dom对象是在程序开发中很实用而且经常会应用到的技术,通过Dom对象可以传递具有树结构的对象,有利用前台页面的诸如树的显示和相应值的处理,本文从两个方面全面解析Dom对象的应用,一是从后台得到完整的D ...

  2. js 鼠标拖拽效果实现

    效果: 源码: <!DOCTYPE html> <html lang="en"> <head> <meta charset="U ...

  3. WeakHashMap源码分析

    WeakHashMap是一种弱引用map,内部的key会存储为弱引用, 当jvm gc的时候,如果这些key没有强引用存在的话,会被gc回收掉, 下一次当我们操作map的时候会把对应的Entry整个删 ...

  4. Go语言内置类型和函数

    内置类型 内置函数 Go 语言拥有一些不需要进行导入操作就可以使用的内置函数.它们有时可以针对不同的类型进行操作,例如:len.cap 和 append,或必须用于系统级的操作,例如:panic.因此 ...

  5. 1. JavaScript学习笔记——JS基础

    1. JavaScript基础 1.1 语法 严格区分大小写 标识符,第一个字符可以是 $,建议使用小驼峰法, 保留字.关键字.true.false.null不能作为标识符 JavaScript是用U ...

  6. Oracle远程数据建物化视图(materialized)创建简单记录,以及DBLINK的创建

    目的:实现远程数据库访问及其相应表的定时同步 一.远程数据库dblink的创建 select * from dba_db_links; select * from user_sys_privs;--查 ...

  7. CAN2.0A帧格式 与 LIN帧格式 简单说明

    一.标准的2.0A帧格式 各字段解释:SOF帧开始标志比特是一个显性比特(0),由一个或多个准备发送帧的节点传输.SOF标志着帧的开始(或仲裁发送帧的权利),并用于“硬同步”总线上的设备.只有在开始发 ...

  8. springMVC的一些入门配置

    1.springMVC的描述 1.1.SpringMVC是Spring框架内置的MVC的实现.SpringMVC就是一个Spring内置的MVC子框架. 1.2.SpringMVC的作用是实现页面和后 ...

  9. js获取字符串字节的位数

    ifSubUser.getBlength = function(str){ ;i--;){ n += str.charCodeAt(i) > ? : ; } return n; }

  10. (转)[InnoDB系列] -- SHOW INNODB STATUS 探秘

    原文:http://imysql.cn/2008_05_22_walk_through_show_innodb_status 很多人让我来阐述一下 SHOW INNODB STATUS 的输出信息, ...