2张表之间通过主键形成一对一映射关系,如一个人只能有一张身份证:
![](http://img.e-com-net.com/image/info8/7df0d465c68949e2900893e86d4bd5bd.jpg)
t_identity_card表建表语句:
CREATE TABLE `t_identity_card` (
`id` int(11) NOT NULL,
`identity` int(11) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=gb2312;
t_person表建表语句:
CREATE TABLE `t_person` (
`id` int(11) NOT NULL,
`name` varchar(255) NOT NULL,
`age` int(11) NOT NULL,
PRIMARY KEY (`id`),
CONSTRAINT `FK_ID` FOREIGN KEY (`id`) REFERENCES `t_identity_card` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=gb2312;
hibernate.cfg.xml:
org.hibernate.dialect.MySQLDialect
com.mysql.jdbc.Driver
jdbc:mysql://localhost:3306/mydb
root
196428
true
单向一对一主键关联:
t_identity_card表:
public class IdentityCard implements Serializable {
private static final long serialVersionUID = 1L;
private int id;
private int identity;
private Person person;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getIdentity() {
return identity;
}
public void setIdentity(int identity) {
this.identity = identity;
}
public Person getPerson() {
return person;
}
public void setPerson(Person person) {
this.person = person;
}
}
由于t_identity_card表使用foreign主键生成策略,故在t_identity_card表的配置文件中必须配置主键生成表t_person,这样在向t_identity_card表中插入数据时才能找到所需的主键值,所以单向一对一主键关联中只有t_person<-t_identity_card,没有t_person->t_identity_card
person
t_person表:
public class Person implements Serializable {
private static final long serialVersionUID = 1L;
private int id;
private String name;
private int age;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
测试一下:
public class Test {
public static void main(String[] args) {
Configuration conf = new Configuration();
SessionFactory sessionFactory = conf.configure().buildSessionFactory();
Session session = sessionFactory.openSession();
IdentityCard identityCard = new IdentityCard();
identityCard.setIdentity(123456);
Person person = new Person();
person.setId(1);
person.setName("sean");
person.setAge(25);
identityCard.setPerson(person);
Transaction tran = session.beginTransaction();
session.save(identityCard);
tran.commit();
IdentityCard identityCard2 = (IdentityCard)session.get(IdentityCard.class, 1);
Person person2 = identityCard2.getPerson();
System.out.println(person2.getName());
session.close();
}
}
测试结果为:
Hibernate: insert into t_identity_card (identity, id) values (?, ?)
sean
只向t_identity_card表中插入了数据,t_person表为空,由于没有设置关联关系的cascade属性,在持久化一张表的时候,并不会级联的持久化另一张表
将t_identity_card表的映射文件中的关联关系修改为:
Hibernate: select person_.id, person_.name as name1_, person_.age as age1_
from t_person person_ where person_.id=?
Hibernate: insert into t_identity_card (identity, id) values (?, ?)
Hibernate: insert into t_person (name, age, id) values (?, ?, ?)
sean
双向一对一主键关联:
这时需要对t_person表的配置做一些修改:
public class Person implements Serializable {
private static final long serialVersionUID = 1L;
private int id;
private String name;
private int age;
private IdentityCard identityCard;//新增
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public IdentityCard getIdentityCard() {
return identityCard;
}
public void setIdentityCard(IdentityCard identityCard) {
this.identityCard = identityCard;
}
}
测试一下:
public class Test {
public static void main(String[] args) {
Configuration conf = new Configuration();
SessionFactory sessionFactory = conf.configure().buildSessionFactory();
Session session = sessionFactory.openSession();
IdentityCard identityCard = new IdentityCard();
identityCard.setIdentity(123456);
Person person = new Person();
person.setId(1);
person.setName("sean");
person.setAge(25);
identityCard.setPerson(person);
person.setIdentityCard(identityCard);
Transaction tran = session.beginTransaction();
session.save(identityCard);
tran.commit();
Person person_tmp = (Person)session.get(Person.class, 1);
IdentityCard id_card_tmp = person_tmp.getIdentityCard();
System.out.println(id_card_tmp.getIdentity());
id_card_tmp = (IdentityCard)session.get(IdentityCard.class, 1);
person_tmp = id_card_tmp.getPerson();
System.out.println(person_tmp.getName());
session.close();
}
}
测试结果为:
Hibernate: select person_.id, person_.name as name1_, person_.age
as age1_ from t_person person_ where person_.id=?
Hibernate: insert into t_identity_card (identity, id) values (?, ?)
Hibernate: insert into t_person (name, age, id) values (?, ?, ?)
123456
sean
Hibernate首先持久化了identityCard对象,将测试代码中的session.save(identityCard)修改为session.save(person),再次测试:
Hibernate: insert into t_person (name, age, id) values (?, ?, ?)
Exception in thread "main" org.hibernate.exception.ConstraintViolationException:
Could not execute JDBC batch update
......
Caused by: java.sql.BatchUpdateException: Cannot add or update a child row:
a foreign key constraint fails (`mydb`.`t_person`, CONSTRAINT `FK_ID`
FOREIGN KEY (`id`) REFERENCES `t_identity_card` (`id`))
......
Hibernate这次首先持久化了person对象,由于t_person表中的id字段建立了外键关系,故持久化失败,删除掉t_person表中id字段的外键关系之后,插入正常:
Hibernate: insert into t_person (name, age, id) values (?, ?, ?)
Hibernate: insert into t_identity_card (identity, id) values (?, ?)
123456
sean
可见Hibernate有时不是很智能,save的对象将会首先被持久化,这时要特别注意表上建立的关联关系