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)不会成功,这是由于数据库中外键约束引起的。

原文地址:https://www.cnblogs.com/tazi/p/2285190.html