最近做的一个工程要用到hibernate的一对一关联,比如论坛的一个主题对应一个作者。 hibernate的一对一关系有两种形式,一种是共享主键方式,另一种是惟一外键方式,因为这里用到的是在主题表里与作者表之间的对应关系,所以介绍的是惟一外键方式的一以一关联。 由于网上很多教程都说得不清楚,给出的实例不能正确运行,所以写下这份笔记,以便以后查询,并与大家分享,如有不对的地方请指正。 本测试使用mysql数据库,eclipse2.1平台,使用tanghan插件生成hbm文件。
1、新建数据库表如下: CREATE TABLE `author` ( `id` int(11) NOT NULL auto_increment, `name` varchar(50) default NULL, PRIMARY KEY (`id`) ); CREATE TABLE `topic` ( `id` int(11) NOT NULL auto_increment, `name` varchar(50) default NULL, `user_id` int(11) default NULL, PRIMARY KEY (`id`) );
2、用tanghan建立数据库连接,并对这两个表生成相应的hbm文件(也可以手工编写这些文件)。 Topic.hbm.xml文件如下: <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 2.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd"> <hibernate-mapping> <class name="model.Topic" table="topic"> <id column="id" length="11" name="id" type="integer"> <generator class="native"/> </id> <property column="name" length="50" name="name" type="string"/> <property column="user_id" length="11" name="user_id" type="integer"/> </class> </hibernate-mapping> Author.hbm.xml文件如下: <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 2.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd"> <hibernate-mapping> <class name="model.Author" table="author"> <id column="id" length="11" name="id" type="integer"> <generator class="native"/> </id> <property column="name" length="50" name="name" type="string"/> </class> </hibernate-mapping> Author.java文件如下: package model; import java.io.Serializable; import org.apache.commons.lang.builder.EqualsBuilder; import org.apache.commons.lang.builder.HashCodeBuilder; import org.apache.commons.lang.builder.ToStringBuilder; /** @author Hibernate CodeGenerator */ public class Author implements Serializable { /** identifier field */ private int id; /** nullable persistent field */ private String name; /** full constructor */ public Author(java.lang.String name) { this.name = name; } /** default constructor */ public Author() { } public int getId() { return this.id; } public void setId(int id) { this.id = id; } public java.lang.String getName() { return this.name; } public void setName(java.lang.String name) { this.name = name; } public String toString() { return new ToStringBuilder(this) .append("id", getId()) .toString(); } public boolean equals(Object other) { if ( !(other instanceof Author) ) return false; Author castOther = (Author) other; return new EqualsBuilder() .append(this.getId(), castOther.getId()) .isEquals(); } public int hashCode() { return new HashCodeBuilder() .append(getId()) .toHashCode(); } } Topic.java文件如下: package model; import java.io.Serializable; import org.apache.commons.lang.builder.EqualsBuilder; import org.apache.commons.lang.builder.HashCodeBuilder; import org.apache.commons.lang.builder.ToStringBuilder; /** @author Hibernate CodeGenerator */ public class Topic implements Serializable { /** identifier field */ private int id; /** nullable persistent field */ private String name; /** nullable persistent field */ private int user_id; /** full constructor */ public Topic(java.lang.String name, int user_id) { this.name = name; this.user_id = user_id; } /** default constructor */ public Topic() { } public int getId() { return this.id; } public void setId(int id) { this.id = id; } public java.lang.String getName() { return this.name; } public void setName(java.lang.String name) { this.name = name; } public int getUser_id() { return this.user_id; } public void setUser_id(int user_id) { this.user_id = user_id; } public String toString() { return new ToStringBuilder(this) .append("id", getId()) .toString(); } public boolean equals(Object other) { if ( !(other instanceof Topic) ) return false; Topic castOther = (Topic) other; return new EqualsBuilder() .append(this.getId(), castOther.getId()) .isEquals(); } public int hashCode() { return new HashCodeBuilder() .append(getId()) .toHashCode(); } }
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类。 /* * 创建日期 2005-8-4 * * TODO 要更改此生成的文件的模板,请转至 * 窗口 - 首选项 - Java - 代码样式 - 代码模板 */ package test; /** * @author hjack<br> * * TODO 要更改此生成的类型注释的模板,请转至 * 窗口 - 首选项 - Java - 代码样式 - 代码模板 */ import net.sf.hibernate.HibernateException; import net.sf.hibernate.Session; import net.sf.hibernate.SessionFactory; import net.sf.hibernate.cfg.Configuration; public class HibernateUtil { private static final SessionFactory sessionFactory; private static Configuration cfg = null; static { try { cfg = new Configuration(); sessionFactory =cfg.configure().buildSessionFactory(); } catch (HibernateException ex) { throw new RuntimeException( "Exception building SessionFactory: " + ex.getMessage(), ex); } } public static final ThreadLocal session = new ThreadLocal(); public static Session currentSession() throws HibernateException { Session s = (Session) session.get(); // Open a new Session, if this Thread has none yet if (s == null) { s = sessionFactory.openSession(); session.set(s); } return s; } public static void closeSession() throws HibernateException { Session s = (Session) session.get(); session.set(null); if (s != null) s.close(); } } hibernate.cfg.xml文件内容如下: <!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD//EN" "http://hibernate.sourceforge.net/hibernate-configuration-2.0.dtd"> <hibernate-configuration> <session-factory> <!--<property name="connection.datasource">java:comp/env/jdbc/mysql</property>--> <property name="dialect">net.sf.hibernate.dialect.MySQLDialect</property> <property name="connection.driver_class">com.mysql.jdbc.Driver</property> <property name="connection.url">jdbc:mysql://localhost/testhibernate</property> <property name="connection.username">root</property> <property name="connection.password"></property> <property name="show_sql">true</property> <!--mapping files--> <mapping resource="model/Author.hbm.xml"></mapping> <mapping resource="model/Topic.hbm.xml"></mapping> </session-factory> </hibernate-configuration>
2)、新建Test类,用于测试。 /* * 创建日期 2005-8-10 * * 更改所生成文件模板为 * 窗口 > 首选项 > Java > 代码生成 > 代码和注释 */ package test; import model.Author; import model.Topic; import net.sf.hibernate.HibernateException; import net.sf.hibernate.Session; import net.sf.hibernate.Transaction; /** * @author hjack * 更改所生成类型注释的模板为 * 窗口 > 首选项 > Java > 代码生成 > 代码和注释 */ public class Test { Session sess; Transaction tx; public void insertTopic(Topic topic,int userID) throws HibernateException{ try{ sess = HibernateUtil.currentSession(); tx = sess.beginTransaction(); //新建一个author对象,并把作者id置入该对象里。 Author author = new Author(); author.setId(userID); //新建一个topic对象,设置用户名和把author对象set进去。 topic.setAuthor(author); //因为只是插入一个话题,并不必在author表中插入一条记录,所以只需save(topic) sess.save(topic); tx.commit(); }catch(HibernateException e){ System.out.println(e.toString()); }finally{ if(tx!=null){ tx.rollback(); } HibernateUtil.closeSession(); } } public void insertAuthor(Author author) throws HibernateException{ try{ sess = HibernateUtil.currentSession(); tx = sess.beginTransaction(); sess.save(author); tx.commit(); }catch(HibernateException e){ System.out.println(e.toString()); }finally{ if(tx!=null){ tx.rollback(); } HibernateUtil.closeSession(); } } public Topic query(int id) throws HibernateException{ Topic topic = null; try{ sess = HibernateUtil.currentSession(); topic=(Topic)sess.load(Topic.class,new Integer(id)); }catch(HibernateException e){ e.printStackTrace(); }finally{ HibernateUtil.closeSession(); } return topic; } public static void main(String[] args) { Test app = new Test(); try { /*测试插入作者 Author author = new Author(); author.setName("jack"); app.insertAuthor(author); */ /*测试插入主题 Topic topic = new Topic(); topic.setName("helloworld."); app.insertTopic(topic,1); */ /*测试查询主题 Topic topic = app.query(1); System.out.println(topic.getAuthor().getName()); */ } catch (Exception e) { // TODO 自动生成 catch 块 e.printStackTrace(); } } }
测试插入作者如图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,与期望相符。
图一
图二 |