工大后院

 找回密码
 加入后院

扫一扫,访问微社区

QQ登录

只需一步,快速开始

搜索
查看: 3402|回复: 16

[原创]hibernate 一对一实践

[复制链接]
发表于 2005-8-17 13:47 | 显示全部楼层 |阅读模式
最近做的一个工程要用到hibernate的一对一关联,比如论坛的一个主题对应一个作者。
hibernate的一对一关系有两种形式,一种是共享主键方式,另一种是惟一外键方式,因为这里用到的是在主题表里与作者表之间的对应关系,所以介绍的是惟一外键方式的一以一关联。
由于网上很多教程都说得不清楚,给出的实例不能正确运行,所以写下这份笔记,以便以后查询,并与大家分享,如有不对的地方请指正。

本测试使用mysql数据库,eclipse2.1平台,使用tanghan插件生成hbm文件。

1、新建数据库表如下:
  1.     CREATE TABLE `author` (
  2.       `id` int(11) NOT NULL auto_increment,
  3.       `name` varchar(50) default NULL,
  4.       PRIMARY KEY  (`id`)
  5.     );
  6.     CREATE TABLE `topic` (
  7.       `id` int(11) NOT NULL auto_increment,
  8.       `name` varchar(50) default NULL,
  9.       `user_id` int(11) default NULL,
  10.       PRIMARY KEY  (`id`)
  11.     );
复制代码


2、用tanghan建立数据库连接,并对这两个表生成相应的hbm文件(也可以手工编写这些文件)。
Topic.hbm.xml文件如下:
  1.     <?xml version="1.0" encoding="UTF-8"?>
  2.     <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 2.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd">
  3.     <hibernate-mapping>
  4.     <class name="model.Topic" table="topic">
  5.     <id column="id" length="11" name="id" type="integer">
  6.     <generator class="native"/>
  7.     </id>
  8.     <property column="name" length="50" name="name" type="string"/>
  9.     <property column="user_id" length="11" name="user_id" type="integer"/>
  10.     </class>
  11.     </hibernate-mapping>
复制代码

   
Author.hbm.xml文件如下:
  1.     <?xml version="1.0" encoding="UTF-8"?>
  2.     <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 2.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd">
  3.     <hibernate-mapping>
  4.     <class name="model.Author" table="author">
  5.     <id column="id" length="11" name="id" type="integer">
  6.     <generator class="native"/>
  7.     </id>
  8.     <property column="name" length="50" name="name" type="string"/>
  9.     </class>
  10.     </hibernate-mapping>
复制代码

   
Author.java文件如下:
  
  1. package model;
  2.    
  3.     import java.io.Serializable;
  4.     import org.apache.commons.lang.builder.EqualsBuilder;
  5.     import org.apache.commons.lang.builder.HashCodeBuilder;
  6.     import org.apache.commons.lang.builder.ToStringBuilder;
  7.    
  8.     /** @author Hibernate CodeGenerator */
  9.     public class Author implements Serializable {
  10.    
  11.         /** identifier field */
  12.         private int id;
  13.    
  14.         /** nullable persistent field */
  15.         private String name;
  16.    
  17.         /** full constructor */
  18.         public Author(java.lang.String name) {
  19.             this.name = name;
  20.         }
  21.    
  22.         /** default constructor */
  23.         public Author() {
  24.         }
  25.    
  26.         public int getId() {
  27.             return this.id;
  28.         }
  29.    
  30.             public void setId(int id) {
  31.                     this.id = id;
  32.             }
  33.    
  34.         public java.lang.String getName() {
  35.             return this.name;
  36.         }
  37.    
  38.             public void setName(java.lang.String name) {
  39.                     this.name = name;
  40.             }
  41.    
  42.         public String toString() {
  43.             return new ToStringBuilder(this)
  44.                 .append("id", getId())
  45.                 .toString();
  46.         }
  47.    
  48.         public boolean equals(Object other) {
  49.             if ( !(other instanceof Author) ) return false;
  50.             Author castOther = (Author) other;
  51.             return new EqualsBuilder()
  52.                 .append(this.getId(), castOther.getId())
  53.                 .isEquals();
  54.         }
  55.    
  56.         public int hashCode() {
  57.             return new HashCodeBuilder()
  58.                 .append(getId())
  59.                 .toHashCode();
  60.         }
  61.    
  62.     }
复制代码

   
Topic.java文件如下:
  
  1. package model;
  2.    
  3.     import java.io.Serializable;
  4.     import org.apache.commons.lang.builder.EqualsBuilder;
  5.     import org.apache.commons.lang.builder.HashCodeBuilder;
  6.     import org.apache.commons.lang.builder.ToStringBuilder;
  7.    
  8.     /** @author Hibernate CodeGenerator */
  9.     public class Topic implements Serializable {
  10.    
  11.         /** identifier field */
  12.         private int id;
  13.    
  14.         /** nullable persistent field */
  15.         private String name;
  16.    
  17.         /** nullable persistent field */
  18.         private int user_id;
  19.    
  20.         /** full constructor */
  21.         public Topic(java.lang.String name, int user_id) {
  22.             this.name = name;
  23.             this.user_id = user_id;
  24.         }
  25.    
  26.         /** default constructor */
  27.         public Topic() {
  28.         }
  29.    
  30.         public int getId() {
  31.             return this.id;
  32.         }
  33.    
  34.             public void setId(int id) {
  35.                     this.id = id;
  36.             }
  37.    
  38.         public java.lang.String getName() {
  39.             return this.name;
  40.         }
  41.    
  42.             public void setName(java.lang.String name) {
  43.                     this.name = name;
  44.             }
  45.    
  46.         public int getUser_id() {
  47.             return this.user_id;
  48.         }
  49.    
  50.             public void setUser_id(int user_id) {
  51.                     this.user_id = user_id;
  52.             }
  53.    
  54.         public String toString() {
  55.             return new ToStringBuilder(this)
  56.                 .append("id", getId())
  57.                 .toString();
  58.         }
  59.    
  60.         public boolean equals(Object other) {
  61.             if ( !(other instanceof Topic) ) return false;
  62.             Topic castOther = (Topic) other;
  63.             return new EqualsBuilder()
  64.                 .append(this.getId(), castOther.getId())
  65.                 .isEquals();
  66.         }
  67.    
  68.         public int hashCode() {
  69.             return new HashCodeBuilder()
  70.                 .append(getId())
  71.                 .toHashCode();
  72.         }
  73.    
  74.     }
复制代码


to be continued
 楼主| 发表于 2005-8-17 13:48 | 显示全部楼层
3、修改Topic.java文件。
找到 private int user_id;
修改成private Author author;
找到 构造函数public Topic(java.lang.String name, int user_id),把参数int user_id改为Author author, 把函数里的this.user_id = user_id; 改为this.author = author;
找到以下两个函数
      public int getUser_id() {
        return this.user_id;
      }
   
            public void setUser_id(int user_id) {
                    this.user_id = user_id;
            }
修改为
            public Author getAuthor() {
                    return author;
            }
   
            public void setAuthor(Author author) {
                    this.author = author;
            }

然后保存。以上文件保存在model包里。

4、修改Topic.hbm.xml文件。
删除下面这行
<property column=\"user_id\" length=\"11\" name=\"user_id\" type=\"integer\"/>
在</class>前添回<many-to-one>项如下
<many-to-one name=\"author\" class=\"model.Author\" column=\"user_id\" unique=\"true\"/>

通过以上操作就建立了Topic表与Author表之间的单向一对一关系,因为本工程中只需要从主题表去了解作者的信息,所以只需要单向的一对一就可以完成了。

5、建立测试用例。
1)、新建test包,在test包内建立HibernateUtil类。
  1.     /*
  2.      * 创建日期 2005-8-4
  3.      *
  4.      * TODO 要更改此生成的文件的模板,请转至
  5.      * 窗口 - 首选项 - Java - 代码样式 - 代码模板
  6.      */
  7.     package test;
  8.    
  9.     /**
  10.      * @author hjack<br>
  11.      *
  12.      * TODO 要更改此生成的类型注释的模板,请转至
  13.      * 窗口 - 首选项 - Java - 代码样式 - 代码模板
  14.      */
  15.    
  16.    
  17.     import net.sf.hibernate.HibernateException;
  18.     import net.sf.hibernate.Session;
  19.     import net.sf.hibernate.SessionFactory;
  20.     import net.sf.hibernate.cfg.Configuration;
  21.    
  22.     public class HibernateUtil {
  23.    
  24.             private static final SessionFactory sessionFactory;
  25.             private static Configuration cfg = null;
  26.    
  27.             static {
  28.                     try {
  29.                             cfg = new Configuration();
  30.                             sessionFactory =cfg.configure().buildSessionFactory();
  31.                     } catch (HibernateException ex) {
  32.                             throw new RuntimeException(
  33.                                     "Exception building SessionFactory: " + ex.getMessage(),
  34.                                     ex);
  35.                     }
  36.             }
  37.    
  38.             public static final ThreadLocal session = new ThreadLocal();
  39.    
  40.             public static Session currentSession() throws HibernateException {
  41.                     Session s = (Session) session.get();
  42.                     // Open a new Session, if this Thread has none yet
  43.                     if (s == null) {
  44.                             s = sessionFactory.openSession();
  45.                             session.set(s);
  46.                     }
  47.                     return s;
  48.             }
  49.    
  50.             public static void closeSession() throws HibernateException {
  51.                     Session s = (Session) session.get();
  52.                     session.set(null);
  53.                     if (s != null)
  54.                             s.close();
  55.             }
  56.     }
复制代码

   
hibernate.cfg.xml文件内容如下:
   
  1. <!DOCTYPE hibernate-configuration PUBLIC
  2.             "-//Hibernate/Hibernate Configuration DTD//EN"
  3.             "http://hibernate.sourceforge.net/hibernate-configuration-2.0.dtd">
  4.     <hibernate-configuration>
  5.             <session-factory>
  6.                     <!--<property name="connection.datasource">java:comp/env/jdbc/mysql</property>-->
  7.                     <property name="dialect">net.sf.hibernate.dialect.MySQLDialect</property>
  8.                     <property name="connection.driver_class">com.mysql.jdbc.Driver</property>
  9.                     <property name="connection.url">jdbc:mysql://localhost/testhibernate</property>
  10.                     <property name="connection.username">root</property>
  11.                     <property name="connection.password"></property>
  12.                     <property name="show_sql">true</property>
  13.                     <!--mapping files-->
  14.                     <mapping resource="model/Author.hbm.xml"></mapping>
  15.                     <mapping resource="model/Topic.hbm.xml"></mapping>
  16.             </session-factory>
  17.     </hibernate-configuration>   
复制代码

要把Author.hbm.xml,Topic.hbm.xml这两个hbm文件写进,否则会找不到类的。

2)、新建Test类,用于测试。
  1.     /*
  2.      * 创建日期 2005-8-10
  3.      *
  4.      * 更改所生成文件模板为
  5.      * 窗口 > 首选项 > Java > 代码生成 > 代码和注释
  6.      */
  7.     package test;
  8.    
  9.     import model.Author;
  10.     import model.Topic;
  11.     import net.sf.hibernate.HibernateException;
  12.     import net.sf.hibernate.Session;
  13.     import net.sf.hibernate.Transaction;
  14.    
  15.     /**
  16.      * @author hjack
  17.      *
  18.      * 更改所生成类型注释的模板为
  19.      * 窗口 > 首选项 > Java > 代码生成 > 代码和注释
  20.      */
  21.     public class Test {
  22.    
  23.             Session sess;
  24.             Transaction tx;
  25.            
  26.             public void insertTopic(Topic topic,int userID) throws HibernateException{
  27.                     try{
  28.                             sess = HibernateUtil.currentSession();
  29.                             tx = sess.beginTransaction();
  30.                             //新建一个author对象,并把作者id置入该对象里。                       
  31.                             Author author = new Author();
  32.                             author.setId(userID);                       
  33.                             //新建一个topic对象,设置用户名和把author对象set进去。
  34.                             topic.setAuthor(author);
  35.                             //因为只是插入一个话题,并不必在author表中插入一条记录,所以只需save(topic)                       
  36.                             sess.save(topic);
  37.                             tx.commit();
  38.                     }catch(HibernateException e){
  39.                             System.out.println(e.toString());
  40.                     }finally{
  41.                             if(tx!=null){
  42.                                     tx.rollback();
  43.                             }
  44.                             HibernateUtil.closeSession();
  45.                     }
  46.             }
  47.            
  48.             public void insertAuthor(Author author) throws HibernateException{
  49.                     try{
  50.                             sess = HibernateUtil.currentSession();
  51.                             tx = sess.beginTransaction();
  52.                             sess.save(author);
  53.                             tx.commit();
  54.                     }catch(HibernateException e){
  55.                             System.out.println(e.toString());
  56.                     }finally{
  57.                             if(tx!=null){
  58.                                     tx.rollback();
  59.                             }
  60.                             HibernateUtil.closeSession();
  61.                     }
  62.             }
  63.    
  64.    
  65.             public Topic query(int id) throws HibernateException{
  66.                     Topic topic = null;
  67.                     try{
  68.                             sess = HibernateUtil.currentSession();   
  69.                             topic=(Topic)sess.load(Topic.class,new Integer(id));   
  70.                     }catch(HibernateException e){
  71.                             e.printStackTrace();
  72.                     }finally{
  73.                             HibernateUtil.closeSession();
  74.                     }
  75.                     return topic;
  76.             }
  77.            
  78.             public static void main(String[] args) {
  79.                    
  80.                     Test app = new Test();
  81.                     try {
  82.                             /*测试插入作者
  83.                             Author author = new Author();
  84.                             author.setName("jack");
  85.                             app.insertAuthor(author);
  86.                             */
  87.                             /*测试插入主题
  88.                             Topic topic = new Topic();
  89.                             topic.setName("helloworld.");
  90.                             app.insertTopic(topic,1);
  91.                             */
  92.                             /*测试查询主题
  93.                             Topic topic = app.query(1);
  94.                             System.out.println(topic.getAuthor().getName());
  95.                             */
  96.                     } catch (Exception e) {
  97.                             // TODO 自动生成 catch 块
  98.                             e.printStackTrace();
  99.                     }
  100.                    
  101.             }
  102.     }
复制代码

测试插入作者如图1所示,测试插入主题如图2所示,测试查询主题结果如下:
Hibernate: select topic0_.id as id1_, topic0_.name as name1_, topic0_.user_id as user_id1_, author1_.id as id0_, author1_.name as name0_ from topic topic0_ left outer join author author1_ on topic0_.user_id=author1_.id where topic0_.id=?
jack
生成的sql语句用到了join,查询结果为jack,与期望相符。
图1

图2


[ Last edited by hjack on 2005-8-17 at 13:56 ]
回复

使用道具 举报

发表于 2005-8-17 14:58 | 显示全部楼层
jackven我来支持你了。我好久没来了。。。

受用。。。
回复

使用道具 举报

发表于 2005-8-17 15:06 | 显示全部楼层
我详细研究下,帮你找下错漏。
回复

使用道具 举报

 楼主| 发表于 2005-8-17 21:47 | 显示全部楼层
呵呵,有什么错漏的地方一定要指出来哦。
回复

使用道具 举报

发表于 2005-8-18 15:26 | 显示全部楼层
可惜我不懂,虽然最近也在研究一下ORMapping
回复

使用道具 举报

发表于 2005-8-18 17:10 | 显示全部楼层
楼上的也来写张原创贴出来啊。
回复

使用道具 举报

发表于 2005-8-18 17:14 | 显示全部楼层
我没楼上那么悠闲
回复

使用道具 举报

发表于 2005-8-18 21:27 | 显示全部楼层
今天上班偷懒去运行的你的hibernate,,,顺便帮你找错漏。。。

结果证实是没错漏的。。。呵呵。。。

为了灌水和帖子好看,我下一贴再说自己的观点。呵呵。

[ Last edited by wool王 on 2005-8-18 at 13:40 ]
回复

使用道具 举报

发表于 2005-8-18 21:39 | 显示全部楼层
首先我不知道你整个项目的宏观情况,包括需求等等,所以可能你这样的设计是有其他的原因的,我仅仅是表达自己的看法而已,呵呵。。。

然后说说我的看法。topic和author是一对一关联的关系,并且你在程序中也已经将author类耦合在topic类中了,但是我发现你在测试用例中使用了:public void insertTopic(Topic topic,int userID) throws HibernateException这么一个方法,我个人感觉不妥,userID好像完全不必要,我觉得userID本身就是包括在topic.getAuthor()里。我感觉面向对象的编程出现了个本应存在于对象内的东西在外头,很别扭。
回复

使用道具 举报

发表于 2005-8-18 21:40 | 显示全部楼层
用程序诠释生命  在 2005/8/18 09:14 发表:

我没楼上那么悠闲


靠!一看你的ID就想扁你。。。
回复

使用道具 举报

 楼主| 发表于 2005-8-18 22:50 | 显示全部楼层
因为在数据库的topic表中,user_id是真实存在的,要保存一条主题记录,必须为它指定一个作者,这是通过user_id来关联的。
而因为在与topic表相对应的类Topic中,已把user_id通过对象author来关联了,所以要保存user_id就要实例一个author对象,通过这个对象来保存user_id至topic表中。
可能这不是很好的方法 ,如果你有其它更好的方法,欢迎来讨论。
回复

使用道具 举报

 楼主| 发表于 2005-8-18 23:00 | 显示全部楼层
理解错你的意思。

对的,可以把userID在执行insertTopic()之前放入topic对象里。
可以这样做:

  1. public void insertTopic(Topic topic) throws HibernateException{
  2.     try{
  3.          sess = HibernateUtil.currentSession();
  4.          tx = sess.beginTransaction();
  5.          sess.save(topic);
  6.           tx.commit();
  7.        }catch(HibernateException e){
  8.               System.out.println(e.toString());
  9.         }finally{
  10.               if(tx!=null){
  11.                    tx.rollback();
  12.               }
  13.               HibernateUtil.closeSession();
  14.          }
  15.       }
复制代码

  1. /*测试插入主题
  2.   Topic topic = new Topic();
  3.   Author author = new Author();
  4.   author.setId(userID);
  5.   topic.setAuthor(author);
  6.   topic.setName("helloworld.");
  7.   app.insertTopic(topic);
  8.   */
复制代码

注:以上代码没有运行过,但我相信是可行的。
回复

使用道具 举报

 楼主| 发表于 2005-8-18 23:03 | 显示全部楼层
你指的是这个意思吧????
回复

使用道具 举报

发表于 2005-8-19 10:24 | 显示全部楼层
大概是这个意思。。。我感觉测试用例像楼上这么写会比较好。。。
回复

使用道具 举报

发表于 2006-5-8 13:08 | 显示全部楼层
原帖由 hjack 于 2005-8-17 13:47 发表
所以介绍的是惟一外键方式的一以一关联


楼主好像忘记在数据厍设置外键了,还是不用设置也可以的?
我不会也不喜欢使用工具生成JAVA代码,楼主做项目是不是常用啊?
把userID在执行insertTopic()之前放入topic对象里,感觉不太好,忘记了怎么办?

楼上不要说我顶旧帖啊,是你叫我看的啊!!
回复

使用道具 举报

发表于 2006-5-8 13:19 | 显示全部楼层
数据库外键可以不设置的...在hibernate关联里面配置就可以了.
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 加入后院

本版积分规则

QQ|Archiver|手机版|小黑屋|广告业务Q|工大后院 ( 粤ICP备10013660号 )

GMT+8, 2024-5-1 04:06

Powered by Discuz! X3.5

Copyright © 2001-2024 Tencent Cloud.

快速回复 返回顶部 返回列表