Hibernate一对一关系映射

第十二章Hibernate一对一关系映射

一对一这种关联本身并不是一件非常复杂的事情,例如:在日常的工作之中肯定做过如下的系统:用户的注册分为快速注册和详细注册,那么如果是快速注册就发现只需要填写注册ID和密码就可以了,而对于详细注册,需要填写更多的内容,并且在以后也可以有用户自己去维护注册的信息。

那么这样的情况(《Oracle开发实战经典》)下,就可以基于一对一的关系实现,做一个单独的user_login表负责快速登录和注册,以及编写一个user_detail表,作为完整的信息。

范例:数据库创建脚本

-- 使用数据库

USE mldn ;

-- 删除表

DROP TABLE user_details ;

DROP TABLE user_login ;

-- 创建表

CREATE TABLE user_login(

       userid                    VARCHAR(50) ,

       password        VARCHAR(32) ,

       CONSTRAINT pk_userid1 PRIMARY KEY(userid)

) ;

CREATE TABLE user_details(

       userid                    VARCHAR(50) ,

       name                    VARCHAR(50) ,

       age                       INT ,

       birthday          DATE ,

       CONSTRAINT pk_userid2 PRIMARY KEY(userid) ,

       CONSTRAINT fk_userid FOREIGN KEY(userid) REFERENCES user_login(userid) ON DELETE CASCADE

) ;

对于此时的数据表也将采用两种方式实现,一种是基于传统的*.hbm.xml文件配置,另一种使用Annotation完成。

12.1、基于*.hbm.xml文件实现一对一的配置

那么首先为项目之中创建Hibernate支持,而后同时选择两张表一起创建Hibernate映射。记得要选择复选框“one-to-one”定义,那么此时生成的POJO类和*.hbm.xml文件几乎可以直接使用。

范例:观察Userlogin.java类的定义

package cn.cgj.pojo;

@SuppressWarnings("serial")

public class UserLogin implements java.io.Serializable {

    private String userid;

    private String password;

    private UserDetails userDetails;    // 一个用户详情

    public UserLogin() {

    }

    //settergetter

}

这个地方发现在一个UserLogin对象里面需要对应一个UserDetails对象,表示一个用户的详情。

范例:观察UserDetails.java类定义

package cn.cgj.pojo;

import java.util.Date;

@SuppressWarnings("serial")

public class UserDetails implements java.io.Serializable {

    private String userid;

    private UserLogin userLogin;    // UserLogin类对应

    private String name;

    private Integer age;

    private Date birthday;

    public UserDetails() {

    }

    //settergetter

}

      但是这个时候不单单是POJO类之间需要产生联系,同时还需要观察*.hbm.xml文件之中所应该产生的联系。

范例:观察userlogin.hbm.xml文件定义

<?xml version="1.0" encoding="utf-8"?>

<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"

"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">

<hibernate-mapping>

    <class name="cn.cgj.pojo.UserLogin" table="user_login" catalog="mldn">

        <id name="userid" type="java.lang.String">

            <column name="userid" length="50" />

            <generator class="assigned"></generator>

        </id>

        <property name="password" type="java.lang.String">

            <column name="password" length="32" />

        </property>

        <!-- 表示一对一的映射,userDetails属性与UserDetails类对应 -->

        <one-to-one name="userDetails" class="cn.cgj.pojo.UserDetails" cascade="all" />

    </class>

</hibernate-mapping>

范例:观察UserDetails.hbm.xml文件定义

<?xml version="1.0" encoding="utf-8"?>

<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"

"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">

<hibernate-mapping>

    <class name="cn.cgj.pojo.UserDetails" table="user_details" catalog="mldn">

        <id name="userid" type="java.lang.String">

            <column name="userid" length="50" />

            <generator class="assigned"></generator>

        </id>

        <!-- 一对一映射,表示userLogin对象是UserLogin类的关联,同时受到UserLogin的约束控制 -->

        <one-to-one name="userLogin" class="cn.cgj.pojo.UserLogin" constrained="true"></one-to-one>

        <property name="name" type="java.lang.String">

            <column name="name" length="50" />

        </property>

        <property name="age" type="java.lang.Integer">

            <column name="age" />

        </property>

        <property name="birthday" type="java.util.Date">

            <column name="birthday" length="10" />

        </property>

    </class>

</hibernate-mapping>

      现在就实现完成了一对一的关系,那么在进行一对一关系的时候,用户通过程序操作应该是以类对象的形式完成的,而后由Hibernate自己去分辨如何保存数据。

范例:增加数据——快速注册

package cn.cgj.pojo;

import cn.cgj.dbc.HibernateSessionFactory;

public class UserLoginTestInsert01 {

    public static void main(String[] args) {

        UserLogin login = new UserLogin();

        login.setUserid("daguo" + System.currentTimeMillis());

        login.setPassword("daguozuibang");

        HibernateSessionFactory.getSession().save(login);

        HibernateSessionFactory.getSession().beginTransaction().commit();

        HibernateSessionFactory.closeSession();

    }

}

Hibernate:

    insert

    into

        mldn.user_login

        (password, userid)

    values

        (?, ?)

      这个时候并没有增加UserDetails类对象,所以此处只实现了user_login数据表内容的保存。

范例:增加数据——详细注册

package cn.cgj.test;

import java.util.Date;

import cn.cgj.dbc.HibernateSessionFactory;

import cn.cgj.pojo.UserDetails;

import cn.cgj.pojo.UserLogin;

public class UserLoginTestInsert02 {

    public static void main(String[] args) {

        UserLogin login = new UserLogin();

        login.setUserid("daguo" + System.currentTimeMillis());

        login.setPassword("daguozuibang");

        UserDetails details = new UserDetails();

        details.setName("大国");

        details.setAge(12);

        details.setBirthday(new Date());

        details.setUserid(login.getUserid());

        login.setUserDetails(details);

        HibernateSessionFactory.getSession().save(login);

        HibernateSessionFactory.getSession().beginTransaction().commit();

        HibernateSessionFactory.closeSession();

    }

}

Hibernate:

    select

        userdetail_.userid,

        userdetail_.name as name0_,

        userdetail_.age as age0_,

        userdetail_.birthday as birthday0_

    from

        mldn.user_details userdetail_

    where

        userdetail_.userid=?

Hibernate:

    insert

    into

        mldn.user_login

        (password, userid)

    values

        (?, ?)

Hibernate:

    insert

    into

        mldn.user_details

        (name, age, birthday, userid)

    values

        (?, ?, ?, ?)

      现在已经成功的实现了数据的增加,但是在此处发现执行的步骤一共有三个:

l  第一个是查询了一下User_details表中的数据。

l  增加User_login表中的数据。

l  增加User_details表中的数据。

但是以上完成了快速注册和完整注册,可是用户一开始选择的是快速注册,那么肯定是需要数据的维护,下面针对于已经保存的快速注册的用户做一个维护。

范例:实现完善注册

package cn.cgj.test;

import java.util.Date;

import cn.cgj.dbc.HibernateSessionFactory;

import cn.cgj.pojo.UserDetails;

import cn.cgj.pojo.UserLogin;

public class UserLoginTestUpdate {

    public static void main(String[] args) {

        UserLogin login = new UserLogin();

        login.setUserid("daguo1457145398037");

        login.setPassword("daguozuibang");

        UserDetails details = new UserDetails();

        details.setName("小国");

        details.setAge(14);

        details.setBirthday(new Date());

        login.setUserDetails(details);

        details.setUserid(login.getUserid());

        HibernateSessionFactory.getSession().update(login);

        HibernateSessionFactory.getSession().beginTransaction().commit();

        HibernateSessionFactory.closeSession();

    }

}

Hibernate:

    select

        userdetail_.userid,

        userdetail_.name as name0_,

        userdetail_.age as age0_,

        userdetail_.birthday as birthday0_

    from

        mldn.user_details userdetail_

    where

        userdetail_.userid=?

Hibernate:

    insert

    into

        mldn.user_details

        (name, age, birthday, userid)

    values

        (?, ?, ?, ?)

Hibernate:

    update

        mldn.user_login

    set

        password=?

    where

        userid=?

Hibernate:

    select

        userdetail_.userid,

        userdetail_.name as name0_,

        userdetail_.age as age0_,

        userdetail_.birthday as birthday0_

    from

        mldn.user_details userdetail_

    where

        userdetail_.userid=?

Hibernate:

    update

        mldn.user_login

    set

        password=?

    where

        userid=?

Hibernate:

    update

        mldn.user_details

    set

        name=?,

        age=?,

        birthday=?

    where

        userid=?

 

      本操作首先还是发出了一个查询,而后发现数据不存在,就直接进行了一条新纪录的增加,随后更新了User_login表记录。User_details表中不存在与主表对应的的数据,那么更新就是增加,如果已经存在了与主表对应的数据,更新就是更新。

范例:查询数据

package cn.cgj.test;

import cn.cgj.dbc.HibernateSessionFactory;

import cn.cgj.pojo.UserLogin;

public class UserLoginTestSelectById {

    public static void main(String[] args) {

        UserLogin login = (UserLogin) HibernateSessionFactory.getSession().get(UserLogin.class, "daguo1457145398037");

        HibernateSessionFactory.closeSession();

        System.out.println(login.getUserid());

        System.out.println(login.getUserDetails().getName());

    }

}

Hibernate:

    select

        userlogin0_.userid as userid1_1_,

        userlogin0_.password as password1_1_,

        userdetail1_.userid as userid0_0_,

        userdetail1_.name as name0_0_,

        userdetail1_.age as age0_0_,

        userdetail1_.birthday as birthday0_0_

    from

        mldn.user_login userlogin0_

    left outer join

        mldn.user_details userdetail1_

            on userlogin0_.userid=userdetail1_.userid

    where

        userlogin0_.userid=?

daguo1457145398037

小国

现在可以发现次查询是一次性完成的,基于left outer join 这个左外连接,而且采用了多表关联查询,所以从性能的角度上来讲也可以感觉到此类方式的性能不咋地,那么有人说了,那能不能使用延迟加载来解决问题呢?遗憾的是延迟加载不能使用,只能为false,所以这个时候应该采用的是一种取数据的配置(fetch)。默认此选项的内容为join(连接查询),可以修改为select,那么同样的操作再次观察结果。

<one-to-one name="userDetails" class="cn.cgj.pojo.UserDetails" cascade="all" fetch="select"/>

这个时候使用了两个查询完成,而且都属于单表操作,那么这种做法就和实际之中的处理情况非常类似了。也就说在使用Hibernate处理关系的时候这一点要特别注意,而基于*.hbm.xml文件的配置也就这一点不好。

范例:删除数据

package cn.cgj.test;

import org.hibernate.Query;

import cn.cgj.dbc.HibernateSessionFactory;

public class UserLoginTestDelete {

   public static void main(String[] args) {

      String hql = "DELETE FROM UserLogin As ul WHERE ul.userid=?";

      Query query = HibernateSessionFactory.getSession().createQuery(hql);

      query.setString(0, "daguo1457145398037");

      System.out.println(query.executeUpdate());

      HibernateSessionFactory.getSession().beginTransaction().commit();

      HibernateSessionFactory.closeSession();

   }

}

Hibernate:

    delete

    from

        mldn.user_login

    where

        userid=?

1

      删除数据的时候直接删除了user_login数据表,但是由于存在外键关联的支持,所以对应的子表记录也将同时被删除。

12.2、基于Annotation实现一对一的配置

      如果使用Annotation实际上会更加的容易一些,唯一的区别也是在创建的时候体现。

范例:观察UserLogin.java类的定义

package cn.cgj.pojo;

import javax.persistence.CascadeType;

import javax.persistence.Column;

import javax.persistence.Entity;

import javax.persistence.FetchType;

import javax.persistence.Id;

import javax.persistence.OneToOne;

import javax.persistence.Table;

@SuppressWarnings("serial")

@Entity

@Table(name = "user_login", catalog = "mldn")

public class UserLogin implements java.io.Serializable {

    private String userid;

    private String password;

    private UserDetails userDetails;

    public UserLogin() {

    }

   

    @Id

    @Column(name = "userid", unique = true, nullable = false, length = 50)

    public String getUserid() {

        return this.userid;

    }

    public void setUserid(String userid) {

        this.userid = userid;

    }

    @Column(name = "password", length = 32)

    public String getPassword() {

        return this.password;

    }

    public void setPassword(String password) {

        this.password = password;

    }

    // 现在进行一对多的关系配置

    @OneToOne(fetch = FetchType.LAZY, mappedBy = "userLogin",cascade=CascadeType.ALL)

    public UserDetails getUserDetails() {

        return this.userDetails;

    }

    public void setUserDetails(UserDetails userDetails) {

        this.userDetails = userDetails;

    }

}

范例:观察UserDetails.java类的定义

package cn.cgj.pojo;

import java.util.Date;

import javax.persistence.Column;

import javax.persistence.Entity;

import javax.persistence.FetchType;

import javax.persistence.Id;

import javax.persistence.OneToOne;

import javax.persistence.PrimaryKeyJoinColumn;

import javax.persistence.Table;

import javax.persistence.Temporal;

import javax.persistence.TemporalType;

@SuppressWarnings("serial")

@Entity

@Table(name = "user_details", catalog = "mldn")

public class UserDetails implements java.io.Serializable {

    private String userid;

    private UserLogin userLogin;

    private String name;

    private Integer age;

    private Date birthday;

    public UserDetails() {

    }

    @Id

    @Column(name = "userid", unique = true, nullable = false, length = 50)

    public String getUserid() {

        return this.userid;

    }

    public void setUserid(String userid) {

        this.userid = userid;

    }

    @OneToOne(fetch = FetchType.LAZY)

    @PrimaryKeyJoinColumn

    public UserLogin getUserLogin() {

        return this.userLogin;

    }

    public void setUserLogin(UserLogin userLogin) {

        this.userLogin = userLogin;

    }

    @Column(name = "name", length = 50)

    public String getName() {

        return this.name;

    }

    public void setName(String name) {

        this.name = name;

    }

    @Column(name = "age")

    public Integer getAge() {

        return this.age;

    }

    public void setAge(Integer age) {

        this.age = age;

    }

    @Temporal(TemporalType.DATE)

    @Column(name = "birthday", length = 10)

    public Date getBirthday() {

        return this.birthday;

    }

    public void setBirthday(Date birthday) {

        this.birthday = birthday;

    }

}

下面就可以采用之前的代码进行测试。

总结

在使用一对一关系配置的时候,如果在处理级联的时候选择错误的方式,那么将直接影响到程序的性能。

基于Annotation的配置,默认情况下都是可以正常使用的配置了。
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值