Hibernate一对一
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)不会成功,这是由于数据库中外键约束引起的。
浙公网安备 33010602011771号