Hibernate的一对一映射(八)
感谢Jie’ blog http://ilog.vip/ ,谢谢他让我有了继续写下去的信念。愿一起坚持,在路上…
上一章简单介绍了Hibernate的一级缓存和二级缓存(七),如果没有看过,请观看上一章
一. Hibernate的一对一映射的使用范围
在Hibernate开发中,一对一的映射虽然使用的少,不如一对多和多对多运用的多,但还是有使用的。 如,如果用户的个人资料太多,可以将用户的重要资料放在一起,私人资料放在一起,即将个人资料进行拆分,而重要资料与私人资料是要进行一对一的关联的。如,用户与个人的住址方式也是一对一的,用户与银行卡也是一对一的,(有一个用户表,银行卡表,这两个表之间也是一对一的),还有最常用举例的,用户与身份证号也是一对一的。
其中一对一映射,有两种方式,一种是共用同一个Id,另外一种是外键映射。
二. 共用Id映射详细步骤
这是简单的使用,用户与身份证号进行相应的举例。按照第一章的方式
的创建相应的工程,搭建Hibernate开发的环境。为User类和IdCard类
二.一 User类和User.hbm.xml的创建
User.java
package com.yjl.pojo;
/**
@author: yuejl
@date: 2018年10月21日 下午12:40:04
@Description 类的相关描述
*/
public class User {
/**
* @param id 标识符Id
* @param userName 用户名
* @param password 密码
* @param description 描述
*/
private Integer id;
private String userName;
private String password;
private String description;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
}
User.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="com.yjl.pojo" >
<!-- 具体的实体类 -->
<class name="User" table="user" lazy="true">
<!-- 主键 -->
<id name="id" column="id">
<generator class="native"></generator>
</id>
<!-- 其余属性 -->
<property name="userName"></property>
<property name="password"></property>
<property name="description"></property>
</class>
</hibernate-mapping>
二. IdCard类和IdCard.hbm.xml的创建
IdCard.java
package com.yjl.pojo;
/**
@author: yuejl
@date: 2018年10月21日 下午12:41:47
@Description 类的相关描述
*/
public class IdCard {
/**
* @param uid 身份证唯一标识符
* @param idNum 身份证标识符
*/
private Integer uid;
private String idNum;
public Integer getUid() {
return uid;
}
public void setUid(Integer uid) {
this.uid = uid;
}
public String getIdNum() {
return idNum;
}
public void setIdNum(String idNum) {
this.idNum = idNum;
}
}
IdCard.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="com.yjl.pojo" >
<!-- 具体的实体类 -->
<class name="IdCard" table="idCard">
<!-- 主键 -->
<id name="uid" column="uid">
<!--这里应该是外键映射-->
<generator class="native"></generator>
</id>
<!-- 其余属性 -->
<property name="idNum"></property>
</class>
</hibernate-mapping>
二.三 在类中添加属性映射
在User.java类中,需要有一个属性来包括IdCard类的对象,即在User.java中添加一个IdCard对象的引用。是一对一的引用。
User.java中添加:
//添加IdCard的一对一的引用
private IdCard card;
public IdCard getCard() {
return card;
}
public void setCard(IdCard card) {
this.card = card;
}
二.四 在User.hbm.xml中添加相对应的属性映射
<!-- 添加与IdCard的一对一映射 -->
<one-to-one name="card" class="com.yjl.pojo.IdCard"></one-to-one>
二.五 在IdCard类中添加User对象引用
//添加对User对象的引用
private User user;
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
二.六 在IdCard.hbm.xml中修改主键生成策略为外键,添加一对一映射
<hibernate-mapping package="com.yjl.pojo" >
<!-- 具体的实体类 -->
<class name="IdCard" table="idCard">
<!-- 主键 -->
<id name="uid" column="uid">
<!--添加外键-->
<generator class="foreign">
<param name="property">user</param>
</generator>
</id>
<!-- 其余属性 -->
<property name="idNum"></property>
<!-- 添加User对象的一对一的引用 修改constrained 约束为true-->
<one-to-one name="user" class="com.yjl.pojo.User" constrained="true"></one-to-one>
</class>
</hibernate-mapping>
二.七 在hibernate.cfg.xml中添加这两个约束文件
<!-- 引入相应的约束文件 ctrl点击时可以正确进入-->
<mapping resource="com/yjl/pojo/User.hbm.xml"/>
<mapping resource="com/yjl/pojo/IdCard.hbm.xml"/>
二.八 测试插入
@Test
public void saveTest(){
//1 得到Session对象
Session session=HibernateUtil.getSession();
//2 打开事务
Transaction tran=session.beginTransaction();
//3 实例化User对象
User user=new User();
user.setUserName("两个蝴蝶飞");
user.setDescription("一个简单的程序员");
//4 实际化IdCard对象
IdCard idCard=new IdCard();
idCard.setIdNum("411421**********");
//5 设置对应关系
user.setCard(idCard);
idCard.setUser(user);
//6 保存对象
session.save(idCard);
session.save(user);
//7 提交事务
tran.commit();
//8 关闭session
session.close();
}
添加约束:
后面就是两条插入语句,insert 语句.
生成的数据表中均有两个数据:
两者的Id是相同的。
二.九 由用户查询身份证测试
/**
* 由用户查询相应的身份证
*/
@Test
public void selectTest1(){
//1 得到Session对象
Session session=HibernateUtil.getSession();
//2 得到User对象
User user=session.get(User.class,1);
System.out.println("姓名为:"+user.getUserName());
//3 得到关联的对象
IdCard idCard=user.getCard();
System.out.println("身份证为:"+idCard.getIdNum());
}
先执行一条外键修改操作:
再执行查询操作:
二.十 由身份证查询用户
/**
* 由身份证查询相应的相对应的用户
*/
@Test
public void selectTest2(){
//1 得到Session对象
Session session=HibernateUtil.getSession();
//2 得到IdCard对象
IdCard idCard=session.get(IdCard.class,1);
System.out.println("身份证为:"+idCard.getIdNum());
//3 得到关联的用户对象
User user=idCard.getUser();
System.out.println("姓名为:"+user.getUserName());
}
这里,先修改外键,然后查询
关联查询,查询出用户的信息
这种方式,每次都要修改外键,造成效率低。而且,如果一旦修改id的话,如将IdCard表中的id进行修改的话,是没有任何现象可以查的。因为,生成的表,实际上是没有任何外键关联的。
这个外键,只是Hibernate自己进行相应的约束,并不是体现在真正的数据库表的。所以一般采用真正的外键约束,也就是第二种方式.
三. 外键约束的一对一详细配置
这种方式的一对一配置,实际上就是一对多的配置,只是多的这一方设置unique=“true”,即是唯一的。多的一方唯一,那么这是一对一了。
外键约束的一对一配置,与上面的基本是相同的,只是相应的配置不一样,即User.hbm.xml与IdCard.hbm.xml有一些不同而已。
将生成的user表与idcard表进行删除。
将User.hbm.xml进行修改为
<hibernate-mapping package="com.yjl.pojo" >
<!-- 具体的实体类 -->
<class name="User" table="user" lazy="true">
<!-- 主键 -->
<id name="id" column="id">
<generator class="native"></generator>
</id>
<!-- 其余属性 -->
<property name="userName"></property>
<property name="password"></property>
<property name="description"></property>
<!-- 添加与IdCard的一对一映射 添加unique为true-->
<many-to-one name="card" class="com.yjl.pojo.IdCard" column="cardId"
unique="true"></many-to-one>
</class>
</hibernate-mapping>
将IdCard.hbm.xml修改为:
<hibernate-mapping package="com.yjl.pojo" >
<!-- 具体的实体类 -->
<class name="IdCard" table="idCard">
<!-- 主键 -->
<id name="uid" column="cardId">
<!--添加外键-->
<generator class="native">
</generator>
</id>
<!-- 其余属性 -->
<property name="idNum"></property>
<!-- 添加User对象的一对一的引用 添加property-ref对应的是User类中的card属性-->
<one-to-one name="user" class="com.yjl.pojo.User"
property-ref="card"></one-to-one>
</class>
</hibernate-mapping>
按照上面所给的saveTest()方法,selectTest1(),selectTest2()进行相应的测试。
saveTest()时,先进行两条创建表的操作,然后是,先删除唯一约束,然后添加唯一约束,最后添加外键。
最后是两条插入的sql语句.
其中IdCard中没有约束,而user表中是存在着约束的:
并且,会在user表中添加一个列,cardId的列
selectTest1()与selectTest2(), 均可以正常的查询出来。
注意点: 有时候,只是在User.hbm.xml中添加相应的约束,而在IdCard.hbm.xml中不添加约束,即在IdCard.hbm.xml中删除这条语句
<!-- 添加User对象的一对一的引用 删除这条语句-->
<one-to-one name="user" class="com.yjl.pojo.User"
property-ref="card"></one-to-one>
这个时候,也是可以正确创建一对一的表的,user表中也存在着唯一索引,但是,这个时候,只能通过用户查询银行卡,即selectTest1()方法通过,是不能通过银行卡查找到相应的用户的,即selectTest2()方法不通过,会报空指向异常的。
建议,两个约束都写。
谢谢!!!