有两种策略可以实现一对一的关联映射:
*主键关联:即让两个对象具有相同的主键值,以表明它们之间的一一对应的关系;数据库表不会有额外的字段来维护它们之间的关系,仅通过表的主键来关联。
*外键关联:外键关联,本来是用于多对一的配置,但是加上唯一的限制之后(采用<many-to-one>标签来映射,指定多的一端unique为true,这样就限制了多的一端的多重性为一),也可以用来表示一对一关联关系,其实它就是多对一的特殊情况。
注意:因为一对一的主键关联映射扩展性不好,当我们的需要发生改变想要将其变为一对多的时候变无法操作了,所以我们遇到一对一关联的时候经常会采用唯一外键关联来解决问题,而很少使用一对一主键关联。
1、XML配置:
本例模仿用户与身份证相对应的关系,即一个用户对应一个身份证信息,且身份证信息不能重复,下面代码是实现基于外键的一对一映射。
(1)主键关联实例
主键关系的重点是:关联的两个实体共享一个主键值。
项目结构:
项目用的是Maven构建的POM.xml文件为:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>Hibernate_demo1</groupId>
<artifactId>com.fendo.cn</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>com.fendo.cn</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.hibernate/hibernate-core -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>5.2.10.Final</version>
</dependency>
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.34</version>
</dependency>
</dependencies>
</project>
SQL语句:
DROP TABLE IF EXISTS `idcard`;
CREATE TABLE `idcard` (
`id` varchar(255) NOT NULL,
`cardNum` varchar(333) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
DROP TABLE IF EXISTS `person`;
CREATE TABLE `person` (
`id` varchar(255) NOT NULL,
`name` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
IdCard.java类
package Hibernate_demo1.com.fendo.Entity;
public class IdCard {
private String id;
private String cardNum;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getCardNum() {
return cardNum;
}
public void setCardNum(String cardNum) {
this.cardNum = cardNum;
}
}
Person.Java类
package Hibernate_demo1.com.fendo.Entity;
public class Person {
private String id;
private String name;
//用户与身份证信息,一对一的关系
private IdCard idCard;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public IdCard getIdCard() {
return idCard;
}
public void setIdCard(IdCard idCard) {
this.idCard = idCard;
}
}
IdCard.hbm.xml映射文件
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="Hibernate_demo1.com.fendo.Entity.IdCard" table="IdCard">
<id name="id" type="java.lang.String">
<column name="id"/>
<generator class="uuid">
</generator>
</id>
<property name="cardNum" column="cardNum"/>
</class>
</hibernate-mapping>
Person.hbm.xml映射文件
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="Hibernate_demo1.com.fendo.Entity.Person" table="person">
<id name="id">
<!--外键生成机制,引用idCard对象的主键作为Person数据表的主键-->
<!-- 采用foreign生成策略,foreign会取得关联对象的标识 -->
<generator class="foreign">
<!-- property只关联对象 -->
<param name="property">idCard</param>
</generator>
</id>
<property name="name"/>
<!--constrained="true"表示person引用了idCard的主键作为外键-->
<!-- one-to-one指示hibernate如何加载其关联对象,默认根据主键加载
也就是拿到关系字段值,根据对端的主键来加载关联对象
-->
<one-to-one name="idCard" constrained="true"/>
</class>
</hibernate-mapping>
HibernateUtils帮助类
package Hibernate_demo1.com.fendo.Util;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
public class HibernateUtils {
private static SessionFactory factory;
static {
try {
//读取hibernate.cfg.xml文件
Configuration cfg = new Configuration().configure();
//建立SessionFactory
factory = cfg.buildSessionFactory();
}catch(Exception e) {
e.printStackTrace();
}
}
public static Session getSession() {
return factory.openSession();
}
public static void closeSession(Session session) {
if (session != null) {
if (session.isOpen()) {
session.close();
}
}
}
public static SessionFactory getSessionFactory() {
return factory;
}
}
App测试类
package Hibernate_demo1.com.fendo.cn;
import org.hibernate.Hibernate;
import org.hibernate.Session;
import Hibernate_demo1.com.fendo.Entity.IdCard;
import Hibernate_demo1.com.fendo.Entity.Person;
import Hibernate_demo1.com.fendo.Util.HibernateUtils;
/**
* Hello world!
*
*/
public class App
{
public static void main( String[] args )
{
Session session = null;
try{
session = HibernateUtils.getSession();
session.beginTransaction();
IdCard idCard = new IdCard();
idCard.setCardNum("111111111");
Person person = new Person();
person.setName("张三");
//建立关联
person.setIdCard(idCard);
//有可能抛出TransientObjectException异常,这是由一对一关联映射的特性决定的,它必须先保存关联对象IdCard
//这样它采用foreign映射策略才能取得关联对象的标识
//也就是它默认了cascade属性
session.save(person);
session.getTransaction().commit();
}catch(Exception e){
e.printStackTrace();
session.getTransaction().rollback();
}finally{
HibernateUtils.closeSession(session);
}
}
}
运行结果如下:
Hibernate:
insert
into
IdCard
(cardNum, id)
values
(?, ?)
Hibernate:
insert
into
person
(name, id)
values
(?, ?)
完整示例:http://download.youkuaiyun.com/detail/u011781521/9832040
(2)外键关联
外键关联的重点是:两个实体各自有不同的主键,但其中一个实体有一个外键引用了另一个表的主键。
修改下person表
DROP TABLE IF EXISTS `person`;
CREATE TABLE `person` (
`id` varchar(255) DEFAULT NULL,
`name` varchar(255) DEFAULT NULL,
`idCard` varchar(255) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Person.hbm.xml文件
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="Hibernate_demo1.com.fendo.Entity.Person" table="person">
<id name="id">
<!--不再是foreign了-->
<generator class="uuid">
<!-- property只关联对象 -->
<param name="property">idCard</param>
</generator>
</id>
<property name="name"/>
<!--唯一的多对一,其实也就变成了一对一关系-->
<many-to-one name="idCard" unique="true"/>
</class>
</hibernate-mapping>
修改下main方法
public class App
{
public static void main( String[] args )
{
Session session = null;
try{
session = HibernateUtils.getSession();
session.beginTransaction();
IdCard idCard = new IdCard();
idCard.setCardNum("111111111");
session.save(idCard);
Person person = new Person();
person.setName("张三");
person.setIdCard(idCard);
session.save(person);
session.getTransaction().commit();
}catch(Exception e){
e.printStackTrace();
session.getTransaction().rollback();
}finally{
HibernateUtils.closeSession(session);
}
}
}
运行效果如下:
Hibernate:
insert
into
IdCard
(cardNum, id)
values
(?, ?)
Hibernate:
insert
into
person
(name, idCard, id)
values
(?, ?, ?)
2.注解版
注解版的和XML配置版的hibernate.cfg.xml相差没多少,就是类的写法不一样,在注解中是这样写的:
<mapping class="Hibernate_demo1.Demo3.Entity.IdCard"></mapping>
<mapping class="Hibernate_demo1.Demo3.Entity.Person"></mapping>
而在xml中是这样写的:
<mapping resource="Hibernate_demo1/com/fendo/Entity/Person.hbm.xml"/>
<mapping resource="Hibernate_demo1/com/fendo/Entity/IdCard.hbm.xml"/>
pom文件为:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>Hibernate_demo1</groupId>
<artifactId>Demo3</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>Demo3</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<!-- https://mvnrepository.com/artifact/junit/junit -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.hibernate/hibernate-core -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>5.2.10.Final</version>
</dependency>
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.34</version>
</dependency>
</dependencies>
</project>
(1)主键关联实例
SQL文件:
CREATE TABLE `Person` (
`id` varchar(255) NOT NULL,
`name` varchar(333) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `cards` (
`id` varchar(255) NOT NULL,
`card_num` varchar(333) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
IdCard文件
package Hibernate_demo1.Demo4.Entity;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToOne;
import javax.persistence.Table;
import org.hibernate.annotations.Parameter;
import org.hibernate.annotations.GenericGenerator;
@Entity
@Table(name="cards")
public class IdCard {
@Id
@Column(name="id")
@GenericGenerator(name="foreignGenerator", strategy="foreign", parameters={@Parameter(value="person", name="property")})
@GeneratedValue(generator="foreignGenerator")
private String id;
@Column(name="card_num")
private String cardNum;
/**
* mappedBy="idCard",其中idCard为Person类中的属性名
*/
@OneToOne(mappedBy="idCard", fetch=FetchType.LAZY)
private Person person;
public Person getPerson() {
return person;
}
public void setPerson(Person person) {
this.person = person;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getCardNum() {
return cardNum;
}
public void setCardNum(String cardNum) {
this.cardNum = cardNum;
}
}
Person类
package Hibernate_demo1.Demo4.Entity;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.OneToOne;
import javax.persistence.PrimaryKeyJoinColumn;
import javax.persistence.Table;
import org.hibernate.annotations.Fetch;
import org.hibernate.annotations.FetchMode;
import org.hibernate.annotations.GenericGenerator;
@Entity
@Table(name="Person")
public class Person {
@Id
@Column(name="id")
@GenericGenerator(name="uuidGenerator",strategy="uuid")
@GeneratedValue(generator="uuidGenerator")
private String id;
@Column(name="name")
private String name;
/**
* cascade表示级联的意思
* FetchMode.SELECT的方式表示,查询与之关联的数据的时候,使用select的方式,而不是左外连接,与在
* 在@OneToOne()中间加上fetch=FetchType.LAZY所表达出来的意思是一样的。
* @PrimaryKeyJoinColumn必须在生产主键的一方指定,不然会在被关联的一方多出一列
*/
@OneToOne(cascade=CascadeType.ALL)
@Fetch(value=FetchMode.SELECT)
@PrimaryKeyJoinColumn
private IdCard idCard;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public IdCard getIdCard() {
return idCard;
}
public void setIdCard(IdCard idCard) {
this.idCard = idCard;
}
}
测试类:
public static void main( String[] args )
{
SessionFactory sessionFactory = new Configuration().configure().buildSessionFactory();
Session session = sessionFactory.getCurrentSession();
Transaction tx = session.beginTransaction();
Person people = new Person();
people.setName("AAA");
IdCard idCard = new IdCard();
idCard.setCardNum("12345");
idCard.setPerson(people);
people.setIdCard(idCard);
session.save(people);
tx.commit();
}
执行效果如下:
Hibernate:
insert
into
Person
(name, id)
values
(?, ?)
Hibernate:
insert
into
cards
(card_num, id)
values
(?, ?)
完整示例:http://download.youkuaiyun.com/detail/u011781521/9832043
(2)外键关联实例
SQL文件:
CREATE TABLE `Person` (
`id` varchar(255) NOT NULL,
`name` varchar(333) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `cards` (
`id` varchar(255) NOT NULL,
`card_num` varchar(333) DEFAULT NULL,
`person_id` varchar(255) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
IdCard文件:
package Hibernate_demo1.Demo3.Entity;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import org.hibernate.annotations.GenericGenerator;
@Entity
@Table(name="cards")
public class IdCard {
@Id
@Column(name="id")
@GenericGenerator(name="uuidGenerator", strategy="uuid")
@GeneratedValue(generator="uuidGenerator")
private String id;
@Column(name="card_num")
private String cardNum;
@ManyToOne(fetch=FetchType.LAZY)
@JoinColumn(name="person_id")
private Person person;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getCardNum() {
return cardNum;
}
public void setCardNum(String cardNum) {
this.cardNum = cardNum;
}
public Person getPerson() {
return person;
}
public void setPerson(Person person) {
this.person = person;
}
}
Person类
package Hibernate_demo1.Demo3.Entity;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.OneToOne;
import javax.persistence.Table;
import org.hibernate.annotations.GenericGenerator;
@Entity
@Table(name="Person")
public class Person {
@Id
@Column(name="id")
@GenericGenerator(name="uuidGenerator", strategy="uuid")
@GeneratedValue(generator="uuidGenerator")
private String id;
@Column(name="name")
private String name;
@OneToOne(cascade={CascadeType.ALL}, fetch=FetchType.LAZY, mappedBy="person")
private IdCard idCard;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public IdCard getIdCard() {
return idCard;
}
public void setIdCard(IdCard idCard) {
this.idCard = idCard;
}
}
测试代码:
package Hibernate_demo1.Demo3.Test;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import Hibernate_demo1.Demo3.Entity.IdCard;
import Hibernate_demo1.Demo3.Entity.Person;
public class Temp {
static Session session;
public static void main(String[] args) {
SessionFactory sessionFactory = new Configuration().configure().buildSessionFactory();
Session session = sessionFactory.getCurrentSession();
session.beginTransaction();
Person people = new Person();
people.setName("AAA");
IdCard idCard = new IdCard();
idCard.setCardNum("889900");
idCard.setPerson(people);
people.setIdCard(idCard);
session.save(people);
session.getTransaction().commit();
}
}
运行效果如下:
Hibernate:
insert
into
Person
(name, id)
values
(?, ?)
Hibernate:
insert
into
cards
(card_num, person_id, id)
values
(?, ?, ?)