1.使用共享主键方式
<class name="com.tazi.domin.User" table="USERS"> <id name="id" type="java.lang.Integer"> <column name="ID"/> <generator class="identity"/> </id> <property name="username" type="string" column="USERNAME"/> <property name="password" type="string" column="PASSWORD"/> <one-to-one name="profile" class="com.tazi.domin.Profile"cascade="none /> </class>
<class name="com.tazi.domin.Profile" table="profile" catalog="hib" > <id name="id" type="java.lang.Integer"> <column name="ID" /> <generator class="foreign" > <param name="property">user</param> </generator> </id> <property name="birth" type="java.sql.Timestamp" column="BIRTHDATE"/> <property name="age" type="java.lang.Integer" column="AGE"/> <one-to-one name="user" class="com.tazi.domin.User" /> </class>
测试:
(1).
profile.setUser(user);//profile的主键依赖于user的主键
user.setProfile(profile);
session.save(user);//user中one-to-one 设置cascade=none
则实际只保存了user,这是显然的。
(2).session.save(user); //user中one-to-one设置cascade=all
则保存user后保存profile
Hibernate: insert into USERS (USERNAME, PASSWORD) values (?, ?) Hibernate: insert into hib.profile (BIRTHDATE, AGE, ID) values (?, ?, ?)
(3). session.save(profile); //profile 的one-to-one中没有进行任何cascade设置,甚至cascade="none"执行结果与(2)相同。因为profile的主键是由表user产生的。
(4).User user=(User)session.get(User.class, 2);发现Hibernate使用两次左外连接,显然有些多余。当session.get(Profile.class,2)时结果也是两次外连接。
Hibernate: select user0_.ID as ID1_2_, user0_.USERNAME as USERNAME1_2_, user0_.PASSWORD as PASSWORD1_2_, profile1_.ID as ID2_0_, profile1_.BIRTHDATE as BIRTHDATE2_0_, profile1_.AGE as AGE2_0_, user2_.ID as ID1_1_, user2_.USERNAME as USERNAME1_1_, user2_.PASSWORD as PASSWORD1_1_ from USERS user0_ left outer join hib.profile profile1_ on user0_.ID=profile1_.ID left outer join USERS user2_ on profile1_.ID=user2_.ID where user0_.ID=?
(5).如果此时在Profile的one-to-one中设置fetch="select",则结果如下:
Hibernate: select user0_.ID as ID1_1_, user0_.USERNAME as USERNAME1_1_, user0_.PASSWORD as PASSWORD1_1_, profile1_.ID as ID2_0_, profile1_.BIRTHDATE as BIRTHDATE2_0_, profile1_.AGE as AGE2_0_ from USERS user0_ left outer join hib.profile profile1_ on user0_.ID=profile1_.ID where user0_.ID=?
可见,在一对一关联中,Hibernate默认使用左外连接的方式进行查询。
(6).在Profile中 增加constrained="true"
<one-to-one name="user" class="com.tazi.domin.User" constrained="true"/>
则User user=(User)session.get(User.class, 2);执行结果如下:
Hibernate: select user0_.ID as ID1_1_, user0_.USERNAME as USERNAME1_1_, user0_.PASSWORD as PASSWORD1_1_, profile1_.ID as ID2_0_, profile1_.BIRTHDATE as BIRTHDATE2_0_, profile1_.AGE as AGE2_0_ from USERS user0_ left outer join hib.profile profile1_ on user0_.ID=profile1_.ID where user0_.ID=?
其实 增加constrained="true",单独获取Profile(session.get(Profile.class,3)),会发现并没有立刻加载User
Hibernate: select profile0_.ID as ID2_0_, profile0_.BIRTHDATE as BIRTHDATE2_0_, profile0_.AGE as AGE2_0_ from hib.profile profile0_ where profile0_.ID=?
(7).delete操作时,会先删除不被其他表引用的表记录
User user=(User)session.get(User.class, 4); session.delete(user);
Hibernate: delete from hib.profile where ID=? Hibernate: delete from USERS where ID=?
2.唯一外键方式
<class name="com.tazi.domin.User" table="USERS"> <id name="id" type="java.lang.Integer"> <column name="ID"/> <generator class="identity"/> </id> <property name="username" type="string" column="USERNAME"/> <property name="password" type="string" column="PASSWORD"/> <one-to-one name="profile" class="com.tazi.domin.Profile" cascade="all" property-ref="user" /> </class> <class name="com.tazi.domin.Profile" table="profile" catalog="hib" > <id name="id" type="java.lang.Integer"> <column name="ID" /> <generator class="identity" /> </id> <property name="birth" type="java.sql.Timestamp" column="BIRTHDATE"/> <property name="age" type="java.lang.Integer" column="AGE"/> <many-to-one name="user" class="com.tazi.domin.User" unique="true" > <column name="USERID"/> </many-to-one> </class>
(1).session.save(user)的执行结果如下:
Hibernate: insert into USERS (USERNAME, PASSWORD) values (?, ?) Hibernate: insert into hib.profile (BIRTHDATE, AGE, USERID) values (?, ?, ?)
(2).session.get(User.class,14)的结果:
Hibernate: select user0_.ID as ID1_1_, user0_.USERNAME as USERNAME1_1_, user0_.PASSWORD as PASSWORD1_1_, profile1_.ID as ID2_0_, profile1_.BIRTHDATE as BIRTHDATE2_0_, profile1_.AGE as AGE2_0_, profile1_.USERID as USERID2_0_ from USERS user0_ left outer join hib.profile profile1_ on user0_.ID=profile1_.USERID where user0_.ID=?
它根据外键取出关联表(profile)的数据
(3)如果在主方(User)的one-to-one配置中去掉property-ref="user",
session.get(User.class,14)的结果如下:
select user0_.ID as ID1_1_, user0_.USERNAME as USERNAME1_1_, user0_.PASSWORD as PASSWORD1_1_, profile1_.ID as ID2_0_, profile1_.BIRTHDATE as BIRTHDATE2_0_, profile1_.AGE as AGE2_0_, profile1_.USERID as USERID2_0_ from USERS user0_ left outer join hib.profile profile1_ on user0_.ID=profile1_.ID where user0_.ID=?
它根据主键相等作为连接条件,显然是错误的。所以必须加上property-ref="user",它指示User在加载关联的Profile时连接条件是通过哪一个属性(默认是id所对应的属性)
(4).session.delete(user)的执行结果与上面1中的delete执行结果相同,都是根据id删除的,而不是根据外键,虽然外键也是唯一的。因为在delete之前,必须先得到数据库中记录对应的持久化对象,取得后id属性一定是已知的。如果在主方(独立方)没有设置cascade="all",则session.delete(user)不会成功,这是由于数据库中外键约束引起的。