Hibernate关联映射1:一对一主键关联

2张表之间通过主键形成一对一映射关系,如一个人只能有一张身份证:

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:

<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
	"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
	"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
	<session-factory>
		<property name="dialect">org.hibernate.dialect.MySQLDialect</property>
		<property name="connection.driver_class">com.mysql.jdbc.Driver</property>
		<property name="connection.url">jdbc:mysql://localhost:3306/mydb</property>
		<property name="connection.username">root</property>
		<property name="connection.password">196428</property>
		
		<property name="hibernate.show_sql">true</property>
		
		<mapping resource="com/po/IdentityCard.hbm.xml" />
		<mapping resource="com/po/Person.hbm.xml" />
	</session-factory>
</hibernate-configuration>

单向一对一主键关联:

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

<?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="com.po.IdentityCard" table="t_identity_card">
    	<id name="id" column="id" type="integer">
			<generator class="foreign">
				<param name="property">person</param>
			</generator>
		</id>
        <property name="identity" column="identity" type="integer"/>
        <one-to-one name="person" class="com.po.Person"/>
    </class>
</hibernate-mapping>

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;
	}
}
<?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="com.po.Person" table="t_person">
		<id name="id" column="id" type="integer">
			<generator class="assigned"/>
		</id>
		<property name="name" column="name" type="string"/>
        <property name="age" column="age" type="integer"/>
    </class>
</hibernate-mapping>

测试一下:

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表的映射文件中的关联关系修改为:<one-to-one name="person" class="com.po.Person"cascade="all" />

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;
	}
}
<?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="com.po.Person" table="t_person">
		<id name="id" column="id" type="integer">
			<generator class="native"/>
		</id>
		<property name="name" column="name" type="string"/>
        <property name="age" column="age" type="integer"/>
    	<!--新增-->
    	<one-to-one name="identityCard" class="com.po.IdentityCard" cascade="all" />
    </class>
</hibernate-mapping>

测试一下:

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的对象将会首先被持久化,这时要特别注意表上建立的关联关系

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值