这篇文章主要谈谈Hibernate的入门开发,例子很简单,就是向数据表中添加用户名和密码。我分别使用了三种方法,一种是直接写代码,写Hbm映射文件等;一种是通过Hbm映射文件来生成代码;一种是通过代码来生成Hbm映射文件。使用了一些自动化工具,XMLBuddy是用来编辑XML文件的,JBoss Eclipse IDE是用来编写Doclet标记的。这篇文章还谈到了一些Eclipse的使用技巧,比如建立“用户库”、“生成 Getter 和 Setter”等。
关于一些软件的使用技巧,我以前的文章都有提及,这里不多说了,必要时会提示一下。
1. 所需软件
● Ant 1.6.2
http://ant.apache.org
● XDoclet 1.2.2
http://xdoclet.sourceforge.net/xdoclet/
● XMLBuddy
http://www.xmlbuddy.com/
● JBoss Eclipse IDE
http://www.jboss.org/products/jbosside
看看说明,需要挑选与使用的eclipse相对应的版本,这里选择
JBossIDE-1.4.1-e30.zip,这是它的镜像下载地址:
● Hibernate
http://www.hibernate.org/
同时也要把
Hibernate Extensions 2.1.3 下载了,它包含一些工具类。
● MySQL 4.1.8
注意需要mysql-connector-java-3.0.16-ga-bin.jar文件
2. 安装和配置
这里着重指出一下,需要在环境变量中设置 ANT_HOME ,并将其指向Ant安装目录,还要在Path变量值中添加 “%ANT_HOME%/bin;” 可以参考
java环境变量设置 。
· XMLBuddy 和Jboss-ide 我都是采用links方式
安装的,
● 建立库文件夹:
在D盘下新建一个java目录,在此目录下新建一个Hibernate子目录,在此子目录下再新建一个lib子目录。
D:/
-java
-Hibernate
-lib
· 将下载的hibernate-2.1.8.zip解压,如解压后的目录名为hibernate-2.1,将这个目录下的hibernate2.jar复制到先前建立的lib目录下,即D:/java/Hibernate/lib目录;
· 然后将hibernate-2.1目录下的lib子目录中的以下文件也复制到这个lib目录下:
jta.jar cglib-full-2.0.2.jar commons-collections-2.1.1.jar commons-logging-1.0.4.jar commons-lang-1.0.1.jar dom4j-1.4.jar ehcache-0.9.jar
log4j-1.2.8.jar odmg-3.0.jar
odmg-3.0.jar
· 解压hibernate-extensions-2.1.3.zip,将其子目录tools中的hibernate-tools.jar和子目录lib中的velocity-1.3.1.jar、jdom.jar 也复制到D:/java/Hibernate/lib目录中
· 解压xdoclet-bin-1.2.2.zip,将其子目录lib中的xdoclet-1.2.2.jar、xdoclet-hibernate-module-1.2.2.jar、xjavadoc-1.1.jar、xdoclet-xdoclet-module-1.2.2.jar 也复制到D:/java/Hibernate/lib目录中
· 最后将mysql-connector-java-3.0.16-ga-bin.jar文件复制到这个lib目录下。
这样,需要用到的库文件已经准备好了,如果认为这样比较麻烦,也可以将jar文件全部复制到lib目录。下面介绍如何在Eclipse中设置“用户库”。
● 设置“用户库”
·窗口 ->首选项 ->Java ->构建路径 ->用户库,
![](http://blog.csdn.net/images/blog_csdn_net/javamxj/111071/o_h1.jpg)
· 然后单击“添加JAR”
![](http://blog.csdn.net/images/blog_csdn_net/javamxj/111071/o_xml2.jpg)
这样,一个用户库文件就做好了,如果要更新Eclipse时,可以将其先导出,然后再导入即可。
这样做,对库文件便于管理,而且如果需要替换或者升级的话都比较方便。
● 设置“构建路径”
· 点击菜单“窗口”->首选项,以下都在“首选项”中配置:
Java->构建路径
![](http://blog.csdn.net/images/blog_csdn_net/javamxj/111071/o_lomboz4.jpg)
这里以一个简单的程序来示范Hibernate的配置与功能,在这个例子中的一些操作,实际上会使用一些自动化工具来完成,而不一定亲自手动操作设定,这边完全手动的原因,在于让你可以知道Hibernate的基本流程。
这是整个项目的结构:
![](http://blog.csdn.net/images/blog_csdn_net/javamxj/111071/o_hib7.jpg)
好了,下面就开始创建项目了。
1. 创建项目
· 新建一个Java项目:HibernateBegin_1,注意选中“创建单独的源文件夹和输出文件夹”。点击“下一步”,切换到“库”,点击“添加库”,如下图:
![](http://blog.csdn.net/images/blog_csdn_net/javamxj/111071/o_hib3.jpg)
· 选择“用户库”
![](http://blog.csdn.net/images/blog_csdn_net/javamxj/111071/o_hib4.jpg)
· 勾选先前设置好的hibernate用户库。
![](http://blog.csdn.net/images/blog_csdn_net/javamxj/111071/o_hib5.jpg)
2. 建立可持久化类
· 下面开始创建一个新类:
User ;包名:
javamxj.hibernate ;
然后添加三个变量(斜体),代码如下:
/* * 采用常规方法开发一个简单的Hibernate实例 * 创建日期 2005-3-31 * @author javamxj(分享java快乐) * @link Blog: htpp://javamxj.mblogger.cn * htpp://blog.csdn.net/javamxj/ */package javamxj.hibernate;public class User { private int id; private String username; private String password; }
· 点击工具栏上的“源代码(S)”,选择其中的“生成 Getter 和 Setter”(右击,在弹出菜单也可选择),如图:
![](http://blog.csdn.net/images/blog_csdn_net/javamxj/111071/o_hib6.jpg)
点击“确定”后,生成如下代码:
/* * 采用常规方法开发一个简单的Hibernate实例 * 创建日期 2005-3-31 * @author javamxj(分享java快乐) * @link Blog: htpp://javamxj.mblogger.cn * htpp://blog.csdn.net/javamxj/ */package javamxj.hibernate;public class User { private int id; private String username; private String password; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; }}
好了,这个类完成了。它是一个普通的Java对象(Plain Old Java Objects,就是POJOs,有时候也称作Plain Ordinary Java Objects),表示一个数据集合。下面建立一个Hbm文件将这个类映射到数据库的表格上。
3. 映射文件
在
javamxj.hibernate包下,新建一个名称为“User.hbm.xml”的文件,使用XMLBuddy编辑它(参考:
利用XMLBuddy在Eclipse中开发XML ),这样比较方便。文件内容如下:
<?xml version="1.0" encoding="GBK"?><!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD//EN" "http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd"> <hibernate-mapping> <class name="javamxj.hibernate.User" table="UserTable"> <id name="id"> <generator class="assigned" /> </id> <property name="username" /> <property name="password" /> </class></hibernate-mapping>
这个XML文件定义了对象属性映射到数据库表的关系,这里采用了assigned(程序设置)方式生成主键。当然还可以使用其它的方式来产生主键,后面的文章就采用了其它的方式产生主键。
<property>标签用于定义Java对象的属性,这里只定义了最简单的方式,由Hibernate自动判断Java对象属性与数据库表名称对应关系。在<property/>标签上的额外设定(像是not null、sql-type等),则可以用于自动产生Java对象与数据库表的工具上。
4. 配置文件
Hibernate可以使用XML或属性文件来进行配置,配置文件名默认为“hibernate.cfg.xml”(或者hibernate.properties)。
在src目录下,新建一个hibernate.cfg.xml文件,内容如下:
<?xml version='1.0' encoding='GBK'?><!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD//EN" "http://hibernate.sourceforge.net/hibernate-configuration-2.0.dtd"><hibernate-configuration> <session-factory> <!-- 是否将运行期生成的SQL输出到日志以供调试 --> <property name="show_sql">true</property> <!-- SQL方言,这里设定的是MySQL --> <property name="dialect">net.sf.hibernate.dialect.MySQLDialect</property> <!-- JDBC驱动程序 --> <property name="connection.driver_class">com.mysql.jdbc.Driver</property> <!-- JDBC URL, "?useUnicode=true&characterEncoding=GBK" 表示使用GBK进行编码 --> <property name="connection.url"> jdbc:mysql://localhost:3306/HibernateTest?useUnicode=true&characterEncoding=GBK </property> <!-- 数据库用户名 --> <property name="connection.username">root</property> <!-- 数据库密码 --> <property name="connection.password">javamxj</property> <!-- 指定User的映射文件 --> <mapping resource="javamxj/hibernate/User.hbm.xml"/> </session-factory></hibernate-configuration>
注意:这里使用的是“jdbc:mysql://localhost:3306/
HibernateTest?useUnicod...”中的
HibernateTest数据库,你需要在MySql中建立这个数据库。
5. 测试程序
在
javamxj.hibernate包下,新建一个Test类,内容如下:
/* * 简单测试一下User类 * 创建日期 2005-3-31 * @author javamxj(分享java快乐) */package javamxj.hibernate;import net.sf.hibernate.*;import net.sf.hibernate.cfg.*;public class Test { public static void main(String[] args) { try { SessionFactory sf = new Configuration().configure() .buildSessionFactory(); Session session = sf.openSession(); Transaction tx = session.beginTransaction(); User user = new User(); user.setUsername("Blog"); user.setPassword("分享java快乐"); session.save(user); tx.commit(); session.close(); } catch (HibernateException e) { e.printStackTrace(); } }}
这里简单说说一下流程,首先初始化Configuration,加载Hibernate的配置信息,然后Configuration取得SessionFactory对象,并由它来开启一个Session,它代表对象与表格的一次会话操作,而 Transaction则表示一组会话操作,我们只需要直接操作User对象,并进行Session与Transaction的相关操作, Hibernate就会自动完成对数据库的操作。
6. 配置数据库
在运行测试程序之前,还必须先设置好数据库。
在MySQL中建立一个HibernateTest数据库,并建立UserTable表
,SQL语句如下:
CREATE TABLE usertable (
ID int(6) NOT NULL auto_increment,
username varchar(24) NOT NULL default '',
password varchar(24) NOT NULL default '',
PRIMARY KEY (ID)
);
ID int(6) NOT NULL auto_increment,
username varchar(24) NOT NULL default '',
password varchar(24) NOT NULL default '',
PRIMARY KEY (ID)
);
这里,HibernateTest与hibernate.cfg.xml配置文件中的HibernateTest相对应,UserTable与hbm映射文件中的UserTable相对应。
7. 运行程序
右击Test.java,点击运行,可以看到控制台输出一系列信息,最后一条输出语句应该是:
Hibernate: insert into UserTable (username, password, id) values (?, ?, ?)
在下篇文章中会介绍如何利用log4j来控制输出信息。
同时,在数据库中可以看到,数据已经添加进表里了:
![](http://blog.csdn.net/images/blog_csdn_net/javamxj/111071/o_hib8.jpg)
小结:
Hibernate原理方面我不想多说,实际上知道也不多,况且这方面的资料很多,比如Hibernate本身自带的中文文档、夏昕编写的《
Hibernate开发指南
》、良葛格编写的“
Hibernate入门
”等都是非常不错的,现在关于Hibetnate的书籍也多了起来。
我所作的工作就是要使新手能尽快上手Hibernate,理论方面我不想过多纠缠,尽量以实例说话。我想,与其凭空说一个技术多好多好,倒不如给我一个可以上手的实例操作一下。好了,不多说废话了。
小结:
Hibernate原理方面我不想多说,实际上知道也不多,况且这方面的资料很多,比如Hibernate本身自带的中文文档、夏昕编写的《
Hibernate开发指南》、良葛格编写的“
Hibernate入门”等都是非常不错的,现在关于Hibetnate的书籍也多了起来。
我所作的工作就是要使新手能尽快上手Hibernate,理论方面我不想过多纠缠,尽量以实例说话。我想,与其凭空说一个技术多好多好,倒不如给我一个可以上手的实例操作一下。好了,不多说废话了。
这篇文章是上篇文章《
Eclipse快速上手Hibernate--1. 入门实例》的延续,主要说的是如何利用Hbm映射文件产生普通的Java对象及数据表。可以参考Hibernate自带的文档《HIBERNATE - 符合Java习惯的关系数据库持久化》的第15章--《工具箱指南》一节。同样,这篇文章没有过多谈理论,只是给出了一个完整的实例加以说明。相关配置请参考
上篇文章。
1. 创建项目
· 新建一个Java项目:HibernateBegin_2,注意选中“创建单独的源文件夹和输出文件夹”,同时添加“用户库”:hibernate。
2. 映射文件User.hbm.xml
· 新建一个包,包名:javamxj.hibernate,然后在此包下新建一个文件,文件名:User.hbm.xml。
User.hbm.xml
|
<?xml version="1.0" encoding="GBK"?><!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD//EN" "http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd"> <hibernate-mapping> <class name="javamxj.hibernate.User" table="UserTable2"> <meta attribute="class-description"> 运行 Hbm2Java 任务, 利用 hbm.xml文件生成Java类文件 @author javamxj(分享java快乐) @link Blog: htpp://javamxj.mblogger.cn htpp://blog.csdn.net/javamxj/ </meta> <id name="id" type="string" unsaved-value="null" length="32" column="ID"> <generator class="uuid.hex"/> </id> <property name="username" type="string" not-null="true" length="24"> <meta attribute="field-description">@param 用户名</meta> </property> <property name="password" type="string" not-null="true" > <column name="密码" length="24" not-null="true"></column> </property> </class></hibernate-mapping> |
● 与
上篇文章中的User.hbm.xml文件比较,可以发现标签上增加了许多额外的设定。
· 这里<meta>标签中的内容将插入到类的javadoc说明去。
· <id>标签使用 uuid.hex 来定义主键的产生算法,UUID算法使用IP地址、JVM的启动时间、系统时间和一个计数值来产生主键。
· <property>标签中的<column>用于生成数据表中的列。
3. 构建文件Build.xml
· 将上篇文章中的“hibernate.cfg.xml”配置文件复制到src目录下。
· 在项目根目录下建立一个build.xml,这个文件含有四个任务,这里会用到“generate-code”、“schemaexport”两个任务,至于用法可以看注释。要注意环境变量的设置要符合自己的实际配置,比如库文件目录的设置是"D:/java/Hibernate/lib",是沿用
上篇文章中的设置。
build.xml
<?xml version="1.0" encoding="GBK"?><project name="利用工具开发Hibernate" default="help" basedir="."> <!-- ****** 环境设置,可以根据自己的实际配置自行更改 ***** --> <!-- 源文件目录, 可以通过 项目->属性->Java构建路径 更改 --> <property name="src.dir" value="./src" /> <!-- 输出的class文件目录,可以通过 项目->属性->Java构建路径 更改 --> <property name="class.dir" value="./bin" /> <!-- 库文件目录 --> <property name="lib.dir" value="D:/java/Hibernate/lib" /> <!-- 定义类路径 --> <path id="project.class.path"> <fileset dir="${lib.dir}"> <include name="*.jar"/> </fileset> <pathelement location="${class.dir}" /> </path> <!-- ************************************************************** --> <!-- 使用说明 --> <!-- ************************************************************** --> <target name="help"> <echo message="利用工具开发Hibernate" /> <echo message="-----------------------------------" /> <echo message="" /> <echo message="提供以下任务:" /> <echo message="" /> <echo message="generate-code --> 运行Hbm2Java,利用 hbm.xml 文件生成Java类文件" /> <echo message="generate-hbm --> 运行HibernateDoclet,生成 Hibernate 类的映射文件" /> <echo message="schemaexport --> 运行SchemaExport,利用 hbm.xml 文件生成数据表" /> <echo message="" /> </target> <!-- ************************************************************** --> <!-- Hbm2Java 任务 --> <!-- ************************************************************** --> <target name="generate-code" > <echo message="运行 Hbm2Java 任务, 利用 hbm.xml 文件生成Java类文件"/> <taskdef name="hbm2java" classname="net.sf.hibernate.tool.hbm2java.Hbm2JavaTask" classpathref="project.class.path"> </taskdef> <hbm2java output="${src.dir}"> <fileset dir="${src.dir}"> <include name="**/*.hbm.xml"/> </fileset> </hbm2java> </target> <!-- ************************************************************** --> <!-- HibernateDoclet 任务 --> <!-- ************************************************************** --> <target name="generate-hbm" > <echo message="运行HibernateDoclet,生成 Hibernate 类的映射文件"/> <taskdef name="hibernatedoclet" classname="xdoclet.modules.hibernate.HibernateDocletTask" classpathref="project.class.path"> </taskdef> <hibernatedoclet destdir="${src.dir}" excludedtags="@version,@author,@todo" force="true" encoding="GBK" verbose="true"> <fileset dir="${src.dir}"> <include name="**/*.java"/> </fileset> <hibernate version="2.0" xmlencoding="GBK" /> </hibernatedoclet> </target> <!-- ************************************************************** --> <!-- SchemaExport 任务 --> <!-- ************************************************************** --> <target name="schemaexport"> <echo message="运行SchemaExport,利用 hbm.xml 文件生成数据表"/> <taskdef name="schemaexport" classname="net.sf.hibernate.tool.hbm2ddl.SchemaExportTask" classpathref="project.class.path"> </taskdef> <schemaexport config="${src.dir}/hibernate.cfg.xml" quiet="no" text="no" drop="no" output="schema-export.sql"> </schemaexport> </target></project>
· 最后的目录结构如下:
![](http://blog.csdn.net/images/blog_csdn_net/javamxj/111071/o_hib10.jpg)
4. 运行任务
· 右击“build.xml” ->“运行” ->这里应该有“Ant 构建”和“Ant 构建...”两个菜单,其中“Ant 构建”直接运行缺省任务,这里是指“help”任务;如果要运行其它的任务,可以通过“Ant 构建...”菜单选择。
· 这里还有一种更好的方法,Eclipse主菜单上点击“窗口” ->“显示视图” ->点击“Ant”,这样就调出了Ant视图,在这个视图窗口的空白处,右击,在弹出菜单中选择“添加构建文件”,然后将HibernateBegin_2项目根目录下的“build.xml”文件载入即可。效果如图:
![](http://blog.csdn.net/images/blog_csdn_net/javamxj/111071/o_hib11.jpg)
这样,想运行某个任务,直接双击Ant视图中的任务即可。
●
生成User.java
· 双击“generate-code”任务,在控制台应该可以看到如下输出:
![](http://blog.csdn.net/images/blog_csdn_net/javamxj/111071/o_hib12.jpg)
· 如果在src目录下没有看到“User.java”这个文件,那么选中src目录,然后按一下“F5”功能键刷新一下src目录,应该可以在包“javamxj.hibernate”下看到“User.java”。这个文件就是“Hbm2Java”生成器根据hbm文件产生的,如下:
User.java
package javamxj.hibernate;import java.io.Serializable;import org.apache.commons.lang.builder.ToStringBuilder;/** * * 运行 Hbm2Java 任务, 利用 hbm.xml文件生成Java类文件 * @author javamxj(分享java快乐) * @link Blog: htpp://javamxj.mblogger.cn * htpp://blog.csdn.net/javamxj/ * */public class User implements Serializable { /** identifier field */ private String id; /** persistent field */ private String username; /** persistent field */ private String password; /** full constructor */ public User(String username, String password) { this.username = username; this.password = password; } /** default constructor */ public User() { } public String getId() { return this.id; } public void setId(String id) { this.id = id; } /** * @param 用户名 */ public String getUsername() { return this.username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return this.password; } public void setPassword(String password) { this.password = password; } public String toString() { return new ToStringBuilder(this) .append("id", getId()) .toString(); }}
可以对照“User.hbm.xml”文件,看看都是哪些属性转化成什么代码。
●
生成数据表
· 启动MySql,应该确定含有HibernateTest数据库,不过这次不需要建立数据表了。
· 双击“schemaexport”任务,控制台输出如下,注意自动生成的SQL语句:
![](http://blog.csdn.net/images/blog_csdn_net/javamxj/111071/o_hib13.jpg)
· 同时,在项目根目录下,也会产生一个“schema-export.sql”文件(如果没有,按F5键刷新目录),这个文件是在“build.xml”中设定的:
schema-export.sql
|
drop table if exists UserTable2 create table UserTable2 ( ID varchar(32) not null, ddd varchar(24) not null, 密码 varchar(24) not null, primary key (ID) ) |
· 切换到数据库中,会发现已经自动产生了数据表usertable2:
![](http://blog.csdn.net/images/blog_csdn_net/javamxj/111071/o_hib14.jpg)
5. 测试程序
好了,将上篇文章中的test.java文件复制到包“javamxj.hibernate”下,然后右击运行这个文件,可以看到数据表中生成的数据。
![](http://blog.csdn.net/images/blog_csdn_net/javamxj/111071/o_hib15.jpg)
小结
好了,再来看看整个项目的结构,其中“User.java”和“schema-export.sql”两个文件都是自动生成的,要注意的一点是:生成“schema-export.sql”文件需要调用“User.java”文件,所以“generate-code”任务要在“schemaexport”任务前执行。
![](http://blog.csdn.net/images/blog_csdn_net/javamxj/111071/o_hib16.jpg)
最好使用XMLBuddy插件来编辑xml文件,可以参考:
关于如何利用Hbm映射文件产生普通的Java对象及数据表,还需要多看看参考文档,也要多加练习,在实践中掌握,在实践中前进。
下篇文章会谈谈利用XDoclet开发Hibernate。
这篇文章是上两篇文章《
Eclipse快速上手Hibernate--1. 入门实例》和《
Eclipse快速上手Hibernate--2. 利用Hbm映射文件开发》的延续,主要说的是如何利用XDocletHbm映射文件产生Hbm映射文件及数据表。可以参考XDoclet文档中关于Hibernate的部分和夏昕编写的《
Hibernate开发指南》。同样,这篇文章没有过多谈理论,只是给出了一个完整的实例加以说明。相关配置请参考
上两篇文章。
1. 创建项目
· 新建一个Java项目:HibernateBegin_3,注意选中“创建单独的源文件夹和输出文件夹”,同时添加“用户库”:hibernate。
2. 文件User.java
· 新建一个类,包名:javamxj.hibernate,类名:User。然后在生成的代码中添加变量,再利用“生成 Getter 和 Setter”,具体方式同《
Eclipse快速上手Hibernate--1. 入门实例 》文章中的编辑User.java的方式一样。
· 添加HibernateDoclet标记,关于如何利用JBoss-IDE添加XDoclet标记的技巧参考《
Eclipse快速上手EJB -- 1. Lomboz + JBoss-IDE 配置2 》文中的关于JBoss-IDE的部分,这是添加HibernateDoclet后的代码:
User.java
/* * 采用HibernateDoclet开发一个简单的Hibernate实例 * 创建日期 2005-3-31 * @author javamxj(分享java快乐) * @link Blog: htpp://javamxj.mblogger.cn * htpp://blog.csdn.net/javamxj/ */package javamxj.hibernate;/** * @hibernate.class table = "UserTable3" */public class User { private int id; private String username; private String password; /** * @hibernate.id * column = "ID" * generator-class = "hilo" */ public int getId() { return id; } public void setId(int id) { this.id = id; } /** * @hibernate.property * length = "24" * not-null = "true" */ public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } /** * @hibernate.property * column = "用户名" * length = "24" * not-null = "true" */ public String getUsername() { return username; } public void setUsername(String username) { this.username = username; }}
· 添加类标记“ @hibernate.class table ="UserTable3" ”用来生成数据库的表UserTable3。
· “ @hibernate.id"用来生成主键,注意这里采用是hilo(高低位)生成器,需要额外的数据库表保存主键生成历史状态。
· “ @hibernate.property”描述POJO中属性与数据库表字段之间的映射关系。
● 更新xdoclet-hibernate-module
· 将XDoclet1.2.2中的xdoclet-hibernate-module-1.2.2.jar复制到JBossIDE-1.4.1-e30/eclipse/plugins/org.jboss.ide.eclipse.xdoclet.core_1.4.1目录中,并且删除其目录下的xdoclet-hibernate-module-1.2.1.jar文件,然后在eclipse界面中,窗口 ->首选项 ->JBoss-IDE ->XDoclet ->Code Assist:点击右侧的“Refresh XDoclet Data”栏,即可完成更新。如果要替换其它的模块,步骤与此类似。
· 将XDoclet1.2.2中的xdoclet-hibernate-module-1.2.2.jar复制到JBossIDE-1.4.1-e30/eclipse/plugins/org.jboss.ide.eclipse.xdoclet.core_1.4.1目录中,并且删除其目录下的xdoclet-hibernate-module-1.2.1.jar文件,然后在eclipse界面中,窗口 ->首选项 ->JBoss-IDE ->XDoclet ->Code Assist:点击右侧的“Refresh XDoclet Data”栏,即可完成更新。如果要替换其它的模块,步骤与此类似。
3. 项目结构
· 将上篇文章中的“build.xml”复制到项目根目录下,配置文件“hibernate.cfg.xml”复制到src目录下,这时的项目结构如图:
![](http://blog.csdn.net/images/blog_csdn_net/javamxj/111071/o_hib21.jpg)
4. 运行任务
· 双击“generate-hbm”任务,然后按一下“F5”功能键刷新一下包“javamxj.hibernate”,应该可以看到这个包下的“User.hbm.xml”。文件如下:
User.hbm.xml
<?
xml
version="1.0"
encoding=
"GBK"
?>
<! DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 2.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd" >
< hibernate-mapping
>
< class
name= " javamxj.hibernate.User "
table= " UserTable3 "
dynamic-update= " false "
dynamic-insert= " false "
select-before-update= " false "
optimistic-lock= " version "
>
< id
name= " id "
column= " ID "
type= " int "
>
< generator class= " hilo " >
<!--
To add non XDoclet generator parameters, create a file named
hibernate-generator-params-User.xml
containing the additional parameters and place it in your merge dir.
-->
</ generator >
</ id >
< property
name= " password "
type= " java.lang.String "
update= " true "
insert= " true "
access= " property "
column= " password "
length= " 24 "
not-null= " true "
/>
< property
name= " username "
type= " java.lang.String "
update= " true "
insert= " true "
access= " property "
column= " 用户名 "
length= " 24 "
not-null= " true "
/>
<!--
To add non XDoclet property mappings, create a file named
hibernate-properties-User.xml
containing the additional properties and place it in your merge dir.
-->
</ class >
</ hibernate-mapping >
<! DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 2.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd" >
< hibernate-mapping
>
< class
name= " javamxj.hibernate.User "
table= " UserTable3 "
dynamic-update= " false "
dynamic-insert= " false "
select-before-update= " false "
optimistic-lock= " version "
>
< id
name= " id "
column= " ID "
type= " int "
>
< generator class= " hilo " >
<!--
To add non XDoclet generator parameters, create a file named
hibernate-generator-params-User.xml
containing the additional parameters and place it in your merge dir.
-->
</ generator >
</ id >
< property
name= " password "
type= " java.lang.String "
update= " true "
insert= " true "
access= " property "
column= " password "
length= " 24 "
not-null= " true "
/>
< property
name= " username "
type= " java.lang.String "
update= " true "
insert= " true "
access= " property "
column= " 用户名 "
length= " 24 "
not-null= " true "
/>
<!--
To add non XDoclet property mappings, create a file named
hibernate-properties-User.xml
containing the additional properties and place it in your merge dir.
-->
</ class >
</ hibernate-mapping >
●
生成数据表
· 启动MySql,应该确定含有HibernateTest数据库,不过这次不需要建立数据表了。
· 双击“schemaexport”任务,然后刷新项目根目录,会发现出产生的“schema-export.sql”文件。
schema-export.sql
|
drop table if exists UserTable3 drop table if exists hibernate_unique_key create table UserTable3 ( ID integer not null, password varchar(24) not null, 用户名 varchar(24) not null, primary key (ID) ) create table hibernate_unique_key ( next_hi integer ) insert into hibernate_unique_key values ( 0 ) |
· 切换到数据库中,会发现已经自动产生了数据表usertable3和hibernate_unique_key:
![](http://blog.csdn.net/images/blog_csdn_net/javamxj/111071/o_hib22.jpg)
5. 测试程序
好了,将上篇文章中的test.java文件复制到包“javamxj.hibernate”下,然后右击运行这个文件,可以看到数据表中生成的数据(图中的数据是连续运行4次后产生的)。
![](http://blog.csdn.net/images/blog_csdn_net/javamxj/111071/o_hib20.jpg)
6. Log4j
Log4j是一个开放源码的项目。它允许开发员以任意的间隔来控制日志的输出。它通过设在外部的配置文件而达到运行时灵活的设置。
运行Log4j的库文件都已经放到先前建立的hibernate库文件夹中了,你只要找到下载的hibernate 2.1.8压缩文件中的etc目录,复制其中的log4j.properties文件到项目中的src目录即可。
运行test.java,可以看到控制台的输出语句似乎和先前没有用Log4j没有什么区别。
现在打开log4j.properties,找到“log4j.logger.net.sf.hibernate=info”语句,将其改成“log4j.logger.net.sf.hibernate=
warn”,再次运行test.java,可以看到控制台的输出语句只有两条了
:
21:03:55,687 WARN Configurator:125 - No configuration found. Configuring ehcache from ehcache-failsafe.xml found in the classpath: jar:file:/D:/java/Hibernate/lib/ehcache-0.9.jar!/ehcache-failsafe.xml
Hibernate: insert into UserTable3 (password, 用户名, ID) values (?, ?, ?)
Hibernate: insert into UserTable3 (password, 用户名, ID) values (?, ?, ?)
警告信息是指缓存配置文件没有找到,以后用到时再谈谈这一点。
好了,hibernate结合Log4j的使用就是这么简单。
关于Log4j的使用,比较简单,网上的资料也很多,自己可以google一下。
小结:
Hibernate的开发相当灵活,可以采用多种方式开发。
· 只有Hbm映射文件:映射文件---hbm2java----java---SchemaExport----数据表
· 只有Java: java---XDoclet---Hbm----SchemaExport----数据表
· 如果只有数据表呢?可以采用Middlegen:
数据表---Middlegen---Hbm----hbm2java----java
关于利用Middlegen开发Hibernate的方法,可以参考夏昕编写的《
Hibernate开发指南》。
· 至于有关Hibernate的Eclipse插件,也有很多,可以看看《
Working with Hibernate in Eclipse》。
前面的《
Eclipse快速上手Hibernate--1. 入门实例 》等三篇文章已经谈了Hibernate的入门以及利用工具创建的方法。这篇文章主要说说在Hibernate中的继承映射。相关配置请参考
前三篇文章。
如果程序中的对象含有继承的关系,在Hibernate中有以下三种策略将这种关系映射到数据表上:
· 每个类层次结构一个表(table per class hierarchy)
· 每个子类一个表(table per subclass)
· 每个具体类一个表(table per concrete class)(有一些限制)
· 每个具体类一个表(table per concrete class)(有一些限制)
每个类层次结构一个表的方式是将所有继承同一父类别的对象储存在同一个表格中,为了做到这一点,需要在表格中使用识别字段来表示某一列(row)是属于某个子类别或父类别,在这个主题中我们将先说明这个方法。
1. 创建项目
· 新建一个Java项目:InheritanceMapping,注意选中“创建单独的源文件夹和输出文件夹”,同时添加“用户库”:hibernate。
2. 编写类文件
· 新建一个类,包名:javamxj.inheritance.one,类名:Animal。然后在生成的代码中添加变量,再利用“生成 Getter 和 Setter”,具体方式同《
Eclipse快速上手Hibernate--1. 入门实例 》文章中的编辑User.java的方式一样。
Animal.java
/* * Hibernate - 继承映射(每个类层次一个表) * 创建日期 2005-4-9 * @author javamxj(分享java快乐) * @link Blog: htpp://javamxj.mblogger.cn * htpp://blog.csdn.net/javamxj/ */package javamxj.inheritance.one;/** * @hibernate.class * table="Animal" * discriminator-value="Animal" * @hibernate.discriminator * column="ANIMAL_TYPE" * type="string" * length = "10" */public abstract class Animal { private Long id; private String name; /** * @hibernate.id * column="ID" * generator-class="hilo" * unsaved-value="null" */ public Long getId() { return id; } public void setId(Long id) { this.id = id; } /** * @hibernate.property * length = "24" */ public String getName() { return name; } public void setName(String name) { this.name = name; } public abstract void makeSound();}
· 这个类是父类,值得注意是在类层次标记中添加了一个discriminator标记,并用它定义了一个字段“ANIMAL_TYPE”,这个字段就是用来识别某一列(row)是属于某个子类别或父类别的。
· 子类Cat.java
Cat.java
|
package javamxj.inheritance.one;/** * @hibernate.subclass * discriminator-value="Cat" */public class Cat extends Animal { private String FurColor; public void makeSound() { System.out.println("喵喵"); } /** * @hibernate.property * length = "24" */ public String getFurColor() { return FurColor; } public void setFurColor(String furColor) { FurColor = furColor; }} |
· 子类Dog.java
Dog.java
|
package javamxj.inheritance.one;/** * @hibernate.subclass * discriminator-value="Dog" */public class Dog extends Animal { private String category; public void makeSound() { System.out.println("汪汪"); } /** * @hibernate.property * length = "24" */ public String getCategory() { return category; } public void setCategory(String category) { this.category = category; }} |
· 这两个子类都很简单,注意添加的hibernate.subclass的标记,指定其识别字段。
3. 构建文件Build.xml
· 在项目根目录下建立一个build.xml,要注意的是环境变量和数据库的设置要符合自己的实际配置,这里库文件目录的设置是"D:/java/Hibernate/lib",参考文章《 Eclipse快速上手Hibernate--1. 入门实例》中的设置。
· 在项目根目录下建立一个build.xml,要注意的是环境变量和数据库的设置要符合自己的实际配置,这里库文件目录的设置是"D:/java/Hibernate/lib",参考文章《 Eclipse快速上手Hibernate--1. 入门实例》中的设置。
· 在MySQL中需要先建立一个HibernateTest数据库,为了解决中文问题,使用了GBK编码,注意“&amp;”,这是由于XDoclet生成Hibernate配置文件时,会丢失一个“amp;”字符串(一个小Bug)。
· 这里我用build.xml中的“hibernatedoclet”任务直接生成“hibernate.cfg.xml”配置文件。
build.xml
<?xml version="1.0" encoding="GBK"?><project name="Hibernate中的继承映射" default="help" basedir="."> <!-- ****** 环境设置,可以根据自己的实际配置自行更改 ***** --> <!-- 源文件目录, 可以通过 项目->属性->Java构建路径 更改 --> <property name="src.dir" value="./src" /> <!-- 输出的class文件目录,可以通过 项目->属性->Java构建路径 更改 --> <property name="class.dir" value="./bin" /> <!-- 库文件目录 --> <property name="lib.dir" value="D:/java/Hibernate/lib" /> <!-- ****** 数据库设置,可以根据自己的实际配置自行更改 ***** --> <property name="hibernate.dialect" value="net.sf.hibernate.dialect.MySQLDialect"></property> <property name="hibernate.driver" value="com.mysql.jdbc.Driver"></property> <!-- &amp; --> <property name="hibernate.jdbc.url" value="jdbc:mysql://localhost:3306/HibernateTest?useUnicode=true&amp;characterEncoding=GBK"> </property> <property name="hibernate.username" value="root"></property> <property name="hibernate.password" value="javamxj"></property> <property name="hibernate.show.sql" value="true"></property> <!-- 定义类路径 --> <path id="project.class.path"> <fileset dir="${lib.dir}"> <include name="*.jar"/> </fileset> <pathelement location="${class.dir}" /> </path> <!-- ************************************************************** --> <!-- 使用说明 --> <!-- ************************************************************** --> <target name="help"> <echo message="利用工具开发Hibernate" /> <echo message="-----------------------------------" /> <echo message="" /> <echo message="提供以下任务:" /> <echo message="" /> <echo message="generate-hbm --> 运行HibernateDoclet,生成 Hibernate 类的映射文件" /> <echo message="schemaexportt --> 运行SchemaExport,利用 hbm.xml 文件生成数据表" /> <echo message="" /> </target> <!-- ************************************************************** --> <!-- HibernateDoclet 任务 --> <!-- ************************************************************** --> <target name="generate-hbm" > <echo message="运行HibernateDoclet,生成 Hibernate 类的映射文件"/> <taskdef name="hibernatedoclet" classname="xdoclet.modules.hibernate.HibernateDocletTask" classpathref="project.class.path"> </taskdef> <hibernatedoclet destdir="${src.dir}" excludedtags="@version,@author,@todo" force="true" encoding="GBK" verbose="true"> <fileset dir="${src.dir}"> <include name="**/*.java"/> </fileset> <hibernate version="2.0" xmlencoding="GBK" /> <!-- 生成配置文件 --> <hibernatecfg dialect="${hibernate.dialect}" driver="${hibernate.driver}" jdbcUrl="${hibernate.jdbc.url}" userName="${hibernate.username}" password="${hibernate.password}" showSql="${hibernate.show.sql}" xmlencoding="GBK" /> </hibernatedoclet> </target> <!-- ************************************************************** --> <!-- SchemaExport 任务 --> <!-- ************************************************************** --> <target name="schemaexport"> <echo message="运行SchemaExport,利用 hbm.xml 文件生成数据表"/> <taskdef name="schemaexport" classname="net.sf.hibernate.tool.hbm2ddl.SchemaExportTask" classpathref="project.class.path"> </taskdef> <schemaexport config="${src.dir}/hibernate.cfg.xml" quiet="no" text="no" drop="no" output="schema-export.sql"> </schemaexport> </target></project>
· 好了,只要这四个文件就够了,其它的会自动生成的。整个项目的结构如下:
![](http://blog.csdn.net/images/blog_csdn_net/javamxj/111071/o_hib30.jpg)
4. 运行任务
· 双击“generate-hbm”任务,会发现在包中多了一个Animal.hbm.xml文件,在src目录下会多了一个hibernate.cfg.xml文件,如果没有,按F5键刷新一下(这里建议打开Eclipse的“首选项”对话框,在“工作台”中勾选“自动刷新工作空间”和“在构建之前自动保存”这两项,这样以后不用每次都刷新了)。
Animal.hbm.xml
<?xml version="1.0" encoding="GBK"?><!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 2.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd"><hibernate-mapping> <class name="javamxj.inheritance.one.Animal" table="Animal" dynamic-update="false" dynamic-insert="false" select-before-update="false" optimistic-lock="version" discriminator-value="Animal" > <id name="id" column="ID" type="java.lang.Long" unsaved-value="null" > <generator class="hilo"> <!-- To add non XDoclet generator parameters, create a file named hibernate-generator-params-Animal.xml containing the additional parameters and place it in your merge dir. --> </generator> </id> <discriminator column="ANIMAL_TYPE" type="string" length="10" /> <property name="name" type="java.lang.String" update="true" insert="true" access="property" column="name" length="24" /> <!-- To add non XDoclet property mappings, create a file named hibernate-properties-Animal.xml containing the additional properties and place it in your merge dir. --> <subclass name="javamxj.inheritance.one.Cat" dynamic-update="false" dynamic-insert="false" discriminator-value="Cat" > <property name="furColor" type="java.lang.String" update="true" insert="true" access="property" column="furColor" length="24" /> <!-- To add non XDoclet property mappings, create a file named hibernate-properties-Cat.xml containing the additional properties and place it in your merge dir. --> </subclass> <subclass name="javamxj.inheritance.one.Dog" dynamic-update="false" dynamic-insert="false" discriminator-value="Dog" > <property name="category" type="java.lang.String" update="true" insert="true" access="property" column="category" length="24" /> <!-- To add non XDoclet property mappings, create a file named hibernate-properties-Dog.xml containing the additional properties and place it in your merge dir. --> </subclass> </class></hibernate-mapping>
hibernate.cfg.xml
|
<?xml version="1.0" encoding="GBK"?><!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 2.0//EN" "http://hibernate.sourceforge.net/hibernate-configuration-2.0.dtd"><!-- Generated file - Do not edit! --><hibernate-configuration> <!-- a SessionFactory instance listed as /jndi/name --> <session-factory> <!-- properties --> <property name="dialect">net.sf.hibernate.dialect.MySQLDialect</property> <property name="show_sql">true</property> <property name="use_outer_join">false</property> <property name="connection.username">root</property> <property name="connection.password">javamxj</property> <property name="connection.driver_class">com.mysql.jdbc.Driver</property> <property name="connection.url">jdbc:mysql://localhost:3306/HibernateTest?useUnicode=true&characterEncoding=GBK</property> <!-- mapping files --> <mapping resource="javamxj/inheritance/one/Animal.hbm.xml"/> </session-factory></hibernate-configuration> |
· 双击“schemaexport”任务,在项目根目录下,会产生一个“schema-export.sql”文件。
schema-export.sql
|
drop table if exists Animal drop table if exists hibernate_unique_key create table Animal ( ID bigint not null, ANIMAL_TYPE varchar(10) not null, name varchar(24), furColor varchar(24), category varchar(24), primary key (ID) ) create table hibernate_unique_key ( next_hi integer ) insert into hibernate_unique_key values ( 0 ) |
· 切换到数据库中,会发现已经自动产生了数据表animal(表hibernate_unique_key是由于采用hilo主键策略生成的)。
![](http://blog.csdn.net/images/blog_csdn_net/javamxj/111071/o_hib31.jpg)
5. 测试程序
· 好了,在包javamxj.inheritance.one下新建一个Demo.java类,很简单,前半部分是添加数据,后半部分是简单的测试。
Demo.java
package javamxj.inheritance.one;import java.util.Iterator;import java.util.List;import net.sf.hibernate.HibernateException;import net.sf.hibernate.Session;import net.sf.hibernate.SessionFactory;import net.sf.hibernate.Transaction;import net.sf.hibernate.cfg.Configuration;public class Demo { public static void main(String[] args) { try { new Demo(); } catch (HibernateException he) { he.printStackTrace(); } } public Demo() throws HibernateException { SessionFactory sf = new Configuration().configure() .buildSessionFactory(); Session sess = sf.openSession(); Transaction tx = null; try { tx = sess.beginTransaction(); Cat cat = new Cat(); cat.setName("小白"); cat.setFurColor("白色"); sess.save(cat); Dog dog = new Dog(); dog.setName("小黑"); dog.setCategory("京巴狗"); sess.save(dog); tx.commit(); } catch (HibernateException e) { if (tx != null) tx.rollback(); throw e; } finally { sess.close(); } sess = sf.openSession(); tx = null; try { tx = sess.beginTransaction(); List animals = sess.find("from " + Animal.class.getName()); for (Iterator it = animals.iterator(); it.hasNext();) { Animal animal = (Animal) it.next(); System.out.println("动物 '" + animal.getName() + "' 所在类是: " + animal.getClass().getName()); System.out.print("发出叫声: "); animal.makeSound(); } tx.commit(); } catch (HibernateException e) { if (tx != null) tx.rollback(); throw e; } finally { sess.close(); } }}
· 运行这个类,控制台输出如下:
![](http://blog.csdn.net/images/blog_csdn_net/javamxj/111071/o_hib32.jpg)
· 同时,数据表中生成如下数据:
![](http://blog.csdn.net/images/blog_csdn_net/javamxj/111071/o_hib33.jpg)
注意其中为“NULL”的部分。
· 最后的项目结构如下:
![](http://blog.csdn.net/images/blog_csdn_net/javamxj/111071/o_hib34.jpg)
小结:
● 优点:
· 实现简单。
· 支持多态——对象角色发生变化,或存在多重角色时。
· 报表操作实现简单:表中包含了所有信息。
· 实现简单。
· 支持多态——对象角色发生变化,或存在多重角色时。
· 报表操作实现简单:表中包含了所有信息。
● 缺点:
· 增加类层次中的耦合。类层次中任何类的属性的增加都会导致表的变更;某个子类属性的修改会影响到整个
层次结构,而不仅仅是该子类。
· 浪费了一些数据库空间。浪费空间的多少取决于继承层次的深度。层次越深,不同的属性越多,属性的全集就越大,也就越浪费空间。
· 可能需要指明具体的角色。
参考:
· HIBERNATE - 符合Java习惯的关系数据库持久化(第8章)
下篇文章会谈谈每个子类一个表的策略。
上篇文章《
Eclipse快速上手Hibernate--4. 继承映射(1) <script language="javascript" type="text/javascript">document.title="Eclipse快速上手Hibernate--4. 继承映射(1) - "+document.title</script>》中已经谈了每个类层次结构一个表(table per class hierarchy)的策略,这篇文章主要说的是每个子类一个表(table per subclass)的策略。一些重复的部分这里就不说了,请参考上篇文章。
1. 创建项目
· 继续沿用上篇文章中所建的Java项目:InheritanceMapping。
2. 编写类文件
· 新建一个类,包名:javamxj.inheritance.two,类名:Animal。然后在生成的代码中添加变量,再利用“生成 Getter 和 Setter”,具体方式同《
Eclipse快速上手Hibernate--1. 入门实例 》文章中的编辑User.java的方式一样。
· 这个类是父类,只是生成一个简单的表。
Vehicle.java
/* * Hibernate - 继承映射(每个子类一个表) * 创建日期 2005-4-9 * @author javamxj(分享java快乐) * @link Blog: htpp://javamxj.mblogger.cn * htpp://blog.csdn.net/javamxj/ */package javamxj.inheritance.two;/** * @hibernate.class */public class Vehicle { private Long id; private String name; /** * @hibernate.id * column="ID" * generator-class="hilo" * unsaved-value="null" */ public Long getId() { return id; } public void setId(Long id) { this.id = id; } /** * @hibernate.property * length = "24" */ public String getName() { return name; } public void setName(String name) { this.name = name; }}
· 子类Car.java
Car.java
|
package javamxj.inheritance.two;/** * @hibernate.joined-subclass * @hibernate.joined-subclass-key * column="id" */public class Car extends Vehicle { private String seat; /** * @hibernate.property * column = "载客" * length = "24" */ public String getSeat() { return seat; } public void setSeat(String seat) { this.seat = seat; }} |
· 子类Truck.java
Truck.java
|
package javamxj.inheritance.two;/** * @hibernate.joined-subclass * @hibernate.joined-subclass-key * column="id" */public class Truck extends Vehicle { private String load; /** * @hibernate.property * column = "载重" * length = "24" */ public String getLoad() { return load; } public void setLoad(String load) { this.load = load; }} |
· 这两个子类都很简单,注意添加的hibernate.joined-subclass的标记。
· 好了,这时整个项目的结构如下:
![](http://blog.csdn.net/images/blog_csdn_net/javamxj/111071/o_hib41.jpg)
3. 运行任务
· 双击“generate-hbm”任务,会发现在包中多了一个Vehicle.hbm.xml文件。如果没有,按F5键刷新一下(这里建议打开Eclipse的“首选项”对话框,在“工作台”中勾选“自动刷新工作空间”和“在构建之前自动保存”这两项,这样以后不用每次都刷新了)。
Vehicle.hbm.xml
<?xml version="1.0" encoding="GBK"?><!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 2.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd"><hibernate-mapping> <class name="javamxj.inheritance.two.Vehicle" dynamic-update="false" dynamic-insert="false" select-before-update="false" optimistic-lock="version" > <id name="id" column="ID" type="java.lang.Long" unsaved-value="null" > <generator class="hilo"> <!-- To add non XDoclet generator parameters, create a file named hibernate-generator-params-Vehicle.xml containing the additional parameters and place it in your merge dir. --> </generator> </id> <property name="name" type="java.lang.String" update="true" insert="true" access="property" column="name" length="24" /> <!-- To add non XDoclet property mappings, create a file named hibernate-properties-Vehicle.xml containing the additional properties and place it in your merge dir. --> <joined-subclass name="javamxj.inheritance.two.Truck" dynamic-update="false" dynamic-insert="false" > <key column="id" /> <property name="load" type="java.lang.String" update="true" insert="true" access="property" column="载重" length="24" /> </joined-subclass> <joined-subclass name="javamxj.inheritance.two.Car" dynamic-update="false" dynamic-insert="false" > <key column="id" /> <property name="seat" type="java.lang.String" update="true" insert="true" access="property" column="载客" length="24" /> </joined-subclass> </class></hibernate-mapping>
· 重点是看看“joined-subclass”标签。
· 同时在hibernate.cfg.xml文件中会自动添加一个映射文件信息:
<mapping resource="javamxj/inheritance/two/Vehicle.hbm.xml"/>
· 先运行MySQL,然后双击“schemaexport”任务,在项目根目录下,会更新“schema-export.sql”文件。
打开这个文件,会发现添加了以下一些语句。
create table Car (
id bigint not null,
载客 varchar(24),
primary key (id)
)
id bigint not null,
载客 varchar(24),
primary key (id)
)
create table Truck (
id bigint not null,
载重 varchar(24),
primary key (id)
)
create table Vehicle (
ID bigint not null,
name varchar(24),
primary key (ID)
)
id bigint not null,
载重 varchar(24),
primary key (id)
)
create table Vehicle (
ID bigint not null,
name varchar(24),
primary key (ID)
)
· 切换到数据库中,会发现已经自动产生了数据表Car、Truck、Vehicle。
![](http://blog.csdn.net/images/blog_csdn_net/javamxj/111071/o_hib42.jpg)
· 将数据表与映射文件Vehicle.hbm.xml对照看看,可以更好的理解每个子类一个表的策略。
4. 测试程序
· 好了,在包javamxj.inheritance.two下新建一个Demo.java类,很简单,前半部分是添加数据,后半部分是简单的测试。
Demo.java
/* * Hibernate - 继承映射(每个子类一个表) * 创建日期 2005-4-9 * @author javamxj(分享java快乐) * @link Blog: htpp://javamxj.mblogger.cn * htpp://blog.csdn.net/javamxj/ */package javamxj.inheritance.two;import java.util.Iterator;import java.util.List;import net.sf.hibernate.HibernateException;import net.sf.hibernate.Session;import net.sf.hibernate.SessionFactory;import net.sf.hibernate.Transaction;import net.sf.hibernate.cfg.Configuration;public class Demo { public static void main(String[] args) { try { new Demo(); } catch (HibernateException he) { he.printStackTrace(); } } public Demo() throws HibernateException { SessionFactory sf = new Configuration().configure() .buildSessionFactory(); Session sess = sf.openSession(); Transaction tx = null; try { tx = sess.beginTransaction(); Car car = new Car(); car.setName("奇瑞QQ"); car.setSeat("4人"); sess.save(car); Truck truck = new Truck(); truck.setName("一汽解放"); truck.setLoad("10吨"); sess.save(truck); tx.commit(); } catch (HibernateException e) { if (tx != null) tx.rollback(); throw e; } finally { sess.close(); } sess = sf.openSession(); tx = null; try { tx = sess.beginTransaction(); List pets = sess.find("from " + Vehicle.class.getName()); for (Iterator it = pets.iterator(); it.hasNext();) { Vehicle vehicle = (Vehicle) it.next(); System.out.println("车型 " + vehicle.getName() + " its class is: " + vehicle.getClass().getName()); } tx.commit(); } catch (HibernateException e) { if (tx != null) tx.rollback(); throw e; } finally { sess.close(); } }}
· 运行这个类,控制台输出如下:
![](http://blog.csdn.net/images/blog_csdn_net/javamxj/111071/o_hib43.jpg)
· 同时,数据表中生成如下数据:
![](http://blog.csdn.net/images/blog_csdn_net/javamxj/111071/o_hib44.jpg)
![](http://blog.csdn.net/images/blog_csdn_net/javamxj/111071/o_hib45.jpg)
![](http://blog.csdn.net/images/blog_csdn_net/javamxj/111071/o_hib46.jpg)
小结:
● 优点:
· 与面向对象的概念的一致性最好。对多态的支持最好,对于对象所可能充当的角色仅需要在相应的表中保存
记录。
· 易于修改基类和增加新的类。
· 与面向对象的概念的一致性最好。对多态的支持最好,对于对象所可能充当的角色仅需要在相应的表中保存
记录。
· 易于修改基类和增加新的类。
· 这种映射几乎有最佳的空间节约性。唯一的容易就是额外的OID,来连接不同的层级层次。
● 缺点:
· 数据库中存在大量的表。
· 访问数据的时间较长。在读写相关的任务上,这种映射方式相当费资源,这个代价还随着继承层次的增多而增大。
· 对报表的支持较差,除非定义视图。
参考:
· HIBERNATE - 符合Java习惯的关系数据库持久化(第8章)
下篇文章会谈谈每个具体类一个表的策略。
前两篇文章《
Eclipse快速上手Hibernate--4. 继承映射(1) <script language="javascript" type="text/javascript">document.title="Eclipse快速上手Hibernate--4. 继承映射(1) - "+document.title</script>》和《
继承映射(2)》中已经谈了每个类层次结构一个表(table per class hierarchy)与每个子类一个表(table per subclass)的策略,这篇文章主要说的是每个具体类一个表(table per concrete class)。一些重复的部分这里就不说了,请参考前两篇文章。
这个策略很简单,抽象的基类不参与映射,具体子类参与映射。
1. 创建项目
· 继续沿用上篇文章中所建的Java项目:InheritanceMapping。
2. 编写类文件
· 新建一个类,包名:javamxj.inheritance.two,类名:Person。然后在生成的代码中添加变量,再利用“生成 Getter 和 Setter”,具体方式同《
Eclipse快速上手Hibernate--1. 入门实例 》文章中的编辑User.java的方式一样。
· 这个类是父类,要注意,这里并没有将父类映射成表。
Person.java
/* * Hibernate - 继承映射(每个具体类一个表) * 创建日期 2005-4-9 * @author javamxj(分享java快乐) * @link Blog: htpp://javamxj.mblogger.cn * htpp://blog.csdn.net/javamxj/ */package javamxj.inheritance.three;public abstract class Person { private Long id; private String name; /** * @hibernate.id * column="ID" * generator-class="hilo" * unsaved-value="null" */ public Long getId() { return id; } public void setId(Long id) { this.id = id; } /** * @hibernate.property * length = "24" */ public String getName() { return name; } public void setName(String name) { this.name = name; }}
· 子类Student.java
Student.java
|
package javamxj.inheritance.three;/** * @hibernate.class * table="Student" */public class Student extends Person { private String studentNumber; /** * @hibernate.property * length = "24" */ public String getStudentNumber() { return studentNumber; } public void setStudentNumber(String studentNumber) { this.studentNumber = studentNumber; }} |
· 子类Professor.java
Professor.java
|
package javamxj.inheritance.three;/** * @hibernate.class * table="Professor" */public class Professor extends Person { private int salary; /** * @hibernate.property */ public int getSalary() { return salary; } public void setSalary(int salary) { this.salary = salary; }} |
· 这两个子类都很简单,跟平常的写法相同,只是简单的映射成一个表。
· 好了,这时整个项目的结构如下:
![](http://blog.csdn.net/images/blog_csdn_net/javamxj/111071/o_hib51.jpg)
3. 运行任务
· 双击“generate-hbm”任务,会发现在包中多了Professor.hbm.xml和Student.hbm.xml两个文件。如果没有,按F5键刷新一下(这里建议打开Eclipse的“首选项”对话框,在“工作台”中勾选“自动刷新工作空间”和“在构建之前自动保存”这两项,这样以后不用每次都刷新了)。
· 这是通过两个子类所生成的映射文件,注意没有生成父类的映射文件,而且这两个子类的映射文件都已经包含了父类的属性。
Professor.hbm.xml
<?xml version="1.0" encoding="GBK"?><!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 2.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd"><hibernate-mapping> <class name="javamxj.inheritance.three.Professor" table="Professor" dynamic-update="false" dynamic-insert="false" select-before-update="false" optimistic-lock="version" > <id name="id" column="ID" type="java.lang.Long" unsaved-value="null" > <generator class="hilo"> <!-- To add non XDoclet generator parameters, create a file named hibernate-generator-params-Professor.xml containing the additional parameters and place it in your merge dir. --> </generator> </id> <property name="salary" type="int" update="true" insert="true" access="property" column="salary" /> <property name="name" type="java.lang.String" update="true" insert="true" access="property" column="name" length="24" /> <!-- To add non XDoclet property mappings, create a file named hibernate-properties-Professor.xml containing the additional properties and place it in your merge dir. --> </class></hibernate-mapping>
Student.hbm.xml
<?xml version="1.0" encoding="GBK"?><!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 2.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd"><hibernate-mapping> <class name="javamxj.inheritance.three.Student" table="Student" dynamic-update="false" dynamic-insert="false" select-before-update="false" optimistic-lock="version" > <id name="id" column="ID" type="java.lang.Long" unsaved-value="null" > <generator class="hilo"> <!-- To add non XDoclet generator parameters, create a file named hibernate-generator-params-Student.xml containing the additional parameters and place it in your merge dir. --> </generator> </id> <property name="studentNumber" type="java.lang.String" update="true" insert="true" access="property" column="studentNumber" length="24" /> <property name="name" type="java.lang.String" update="true" insert="true" access="property" column="name" length="24" /> <!-- To add non XDoclet property mappings, create a file named hibernate-properties-Student.xml containing the additional properties and place it in your merge dir. --> </class></hibernate-mapping>
· 同时在hibernate.cfg.xml文件中会自动添加这两个映射文件信息:
<mapping resource="javamxj/inheritance/three/Professor.hbm.xml"/>
<mapping resource="javamxj/inheritance/three/Student.hbm.xml"/>
<mapping resource="javamxj/inheritance/three/Student.hbm.xml"/>
· 先运行MySQL,然后双击“schemaexport”任务,在项目根目录下,会更新“schema-export.sql”文件。
打开这个文件,会发现添加了以下一些语句。
create table Student (
ID bigint not null,
studentNumber varchar(24),
name varchar(24),
primary key (ID)
)
ID bigint not null,
studentNumber varchar(24),
name varchar(24),
primary key (ID)
)
create table Professor (
ID bigint not null,
salary integer,
name varchar(24),
primary key (ID)
)
ID bigint not null,
salary integer,
name varchar(24),
primary key (ID)
)
· 切换到数据库中,会发现已经自动产生了数据表Student、Professor。
![](http://blog.csdn.net/images/blog_csdn_net/javamxj/111071/o_hib52.jpg)
4. 测试程序
· 好了,在包javamxj.inheritance.two下新建一个Demo.java类,很简单,前半部分是添加数据,后半部分是简单的测试。
Demo.java
/* * Hibernate - 继承映射(每个具体类一个表) * 创建日期 2005-4-9 * @author javamxj(分享java快乐) * @link Blog: htpp://javamxj.mblogger.cn * htpp://blog.csdn.net/javamxj/ */package javamxj.inheritance.three;import java.util.Iterator;import java.util.List;import net.sf.hibernate.HibernateException;import net.sf.hibernate.Session;import net.sf.hibernate.SessionFactory;import net.sf.hibernate.Transaction;import net.sf.hibernate.cfg.Configuration;public class Demo { public static void main(String[] args) { try { new Demo(); } catch (HibernateException he) { he.printStackTrace(); } } public Demo() throws HibernateException { SessionFactory sf = new Configuration().configure() .buildSessionFactory(); Session sess = sf.openSession(); Transaction tx = null; try { tx = sess.beginTransaction(); Student student = new Student(); student.setName("张三"); student.setStudentNumber("1234554321"); sess.save(student); Professor professor = new Professor(); professor.setName("李四"); professor.setSalary(4300); sess.save(professor); tx.commit(); } catch (HibernateException e) { if (tx != null) tx.rollback(); throw e; } finally { sess.close(); } sess = sf.openSession(); tx = null; try { tx = sess.beginTransaction(); List person = sess.find("from " + Person.class.getName()); for (Iterator it = person.iterator(); it.hasNext();) { Person p = (Person) it.next(); System.out.println("人员 '" + p.getName() + "' its class is: " + p.getClass().getName()); } tx.commit(); } catch (HibernateException e) { if (tx != null) tx.rollback(); throw e; } finally { sess.close(); } }}
· 运行这个类,控制台输出如下:
![](http://blog.csdn.net/images/blog_csdn_net/javamxj/111071/o_hib53.jpg)
· 同时,数据表中生成如下数据:
![](http://blog.csdn.net/images/blog_csdn_net/javamxj/111071/o_hib54.jpg)
![](http://blog.csdn.net/images/blog_csdn_net/javamxj/111071/o_hib55.jpg)
小结:
● 优点:
· 报表操作实现简单:表中包含了具体子类的所有信息。
· 报表操作实现简单:表中包含了具体子类的所有信息。
● 缺点:
· 类的修改会导致相对应的表及其子类所对应表的更改。
· 当含有多重子类时,会造成在数据库表格中生成重复的字段。
参考:
· HIBERNATE - 符合Java习惯的关系数据库持久化(第8章)
下篇文章说说组件(Component)映射。
缺5
Hibernate中的关联(Association)映射主要有三种:一对一关联,一对多(或多对一)关联,多对多关联。每种关联都可以分为单向和双向两种。
这篇文章主要说的是在Hibernate中的一对一关联,可以参考Hibernate官方文档的第5章
。至于环境设置,可以参考这个系列的前面几篇文章。
一对一关联有两种映射方式:一种是使用主键关联,限制两个数据表的主键使用相同的值;另一种是一个外键和一个惟一关键字对应。
这里用关联映射将上篇文章
《组件映射》改写了一下,一个人对应一个地址,这是一个单向关联,先谈谈如何使用主键关联。
1. 创建项目
· 新建一个Java项目:AssociationMapping,注意选中“创建单独的源文件夹和输出文件夹”,同时添加“用户库”:hibernate。
2. 编写类文件
· 新建一个类,包名:javamxj.hibernate.association.one2one,类名:Person。
Person.java
/* * Hibernate - 关联(Association)映射 * 创建日期 2005-4-25 * @author javamxj(分享java快乐) * @link Blog: htpp://blog.csdn.net/javamxj/ * htpp://javamxj.mblogger.cn */package javamxj.hibernate.association.one2one;/** * @hibernate.class table = "T_Person" */public class Person { private Long id; private String username; private Address address; /** * @hibernate.id * generator-class="foreign" * @hibernate.generator-param * name="property" * value="address" */ public Long getId() {return id;} public void setId(Long id) {this.id = id;} /** * @hibernate.property * length="15" * not-null="true" */ public String getUsername() {return username;} public void setUsername(String username) {this.username = username;} /** * @hibernate.one-to-one * cascade="all" */ public Address getAddress() {return address;} public void setAddress(Address address) {this.address = address;}}
· 注意Person类的主键生成方式是“foreign”,使其参考Address类的主键。
· 在最后几行中指明了如何引用Address类的方式,其中
cascade="all" 表示所有情况下均进行级联操作。
· 这里将Address类独立映射为一个表。
Address.java
package javamxj.hibernate.association.one2one;/** * @hibernate.class table = "T_Address" */public class Address { private String country; private String city; private String street; private String zipCode; private Long id; public Address() {} public Address(String country, String city, String street, String zipcode) { super(); this.country = country; this.city = city; this.street = street; this.zipCode = zipcode; } /** * @hibernate.id * generator-class="hilo" * unsaved-value="null" */ public Long getId() { return id; } public void setId(Long id) { this.id = id; } /** * @hibernate.property * length = "12" */ public String getCity() {return city;} public void setCity(String city) {this.city = city;} /** * @hibernate.property * length = "12" */ public String getCountry() {return country;} public void setCountry(String country) {this.country = country;} /** * @hibernate.property * length = "6" */ public String getZipCode() {return zipCode;} public void setZipCode(String number) {this.zipCode = number;} /** * @hibernate.property * length = "12" */ public String getStreet() {return street;} public void setStreet(String street) {this.street = street;} }
3. 运行任务
· 复制《
Eclipse快速上手Hibernate--4. 继承映射(1)》文中的build.xml到项目根目录下。
· 双击“generate-hbm”任务,会发现在包中产生了Person.hbm.xml和Address.hbm.xml文件,在src目录下会多了一个hibernate.cfg.xml文件,如果没有,按F5键刷新一下。
· 看看Person类的映射文件中的重点部分:
<generator class="foreign">
<param name="property">address</param>
<!--
To add non XDoclet generator parameters, create a file named
hibernate-generator-params-Person.xml
containing the additional parameters and place it in your merge dir.
-->
</generator>
<param name="property">address</param>
<!--
To add non XDoclet generator parameters, create a file named
hibernate-generator-params-Person.xml
containing the additional parameters and place it in your merge dir.
-->
</generator>
<one-to-one
name="address"
class="javamxj.hibernate.association.one2one.Address"
cascade="all"
outer-join="auto"
constrained="false"
/>
name="address"
class="javamxj.hibernate.association.one2one.Address"
cascade="all"
outer-join="auto"
constrained="false"
/>
· 运行MySql服务器,然后双击“schemaexport”任务,在项目根目录下,会产生一个“schema-export.sql”文件。
· 切换到数据库中,会发现已经自动产生了数据表T_Person和T_Address。
4. 测试程序
· 好了,在包javamxj.hibernate.association.one2one下新建一个Demo.java文件。
Demo.java
package javamxj.hibernate.association.one2one;import net.sf.hibernate.HibernateException;import net.sf.hibernate.Session;import net.sf.hibernate.SessionFactory;import net.sf.hibernate.Transaction;import net.sf.hibernate.cfg.Configuration;public class Demo { public static void main(String[] args) throws HibernateException { Address address1 = new Address("中国", "上海", "普陀", "200055"); Person p1 = new Person(); p1.setUsername("JavaMXJ"); p1.setAddress(address1); Address address2 = new Address("中国", "北京", "海淀", "100086"); Person p2 = new Person(); p2.setUsername("张三"); p2.setAddress(address2); SessionFactory sf = new Configuration().configure().buildSessionFactory(); Session sess = sf.openSession(); Transaction tx= sess.beginTransaction(); sess.save(p1); sess.save(p2); tx.commit(); sess.close(); sf.close(); }}
· 运行这个类,数据表中生成如下数据:
![](http://blog.csdn.net/images/blog_csdn_net/javamxj/111071/o_hib70.jpg)
![](http://blog.csdn.net/images/blog_csdn_net/javamxj/111071/o_hib71.jpg)
注意这两个表中的主键值相同的。
· 最后的项目结构如下:
![](http://blog.csdn.net/images/blog_csdn_net/javamxj/111071/o_hib72.jpg)
5. 另一种映射方式
这里简单说说一个外键和一个惟一关键字对应的方式。
以上面的文章为基础,只要改动一下Person.java即可。
Person.java
/* * Hibernate - 关联(Association)映射 * 创建日期 2005-4-25 * @author javamxj(分享java快乐) * @link Blog: htpp://blog.csdn.net/javamxj/ * htpp://javamxj.mblogger.cn */package javamxj.hibernate.association.one2one;/** * @hibernate.class table = "T_Person" */public class Person { private Long id; private String username; private Address address; /** * @hibernate.id * generator-class="hilo" * unsaved-value="null" */ public Long getId() {return id;} public void setId(Long id) {this.id = id;} /** * @hibernate.property * length="15" * not-null="true" */ public String getUsername() {return username;} public void setUsername(String username) {this.username = username;} /** * @hibernate.many-to-one * column = "fk_Address" * cascade="all" * unique="true" */ public Address getAddress() {return address;} public void setAddress(Address address) {this.address = address;}}
· 需要改动的部分用斜体字标出来了,有两处,一处是定义主键的生成方式,一处是Person类如何引用Address类。
· 看看Person类的映射文件中的相关部分:
<generator class="hilo">
<!--
To add non XDoclet generator parameters, create a file named
hibernate-generator-params-Person.xml
containing the additional parameters and place it in your merge dir.
-->
</generator>
<!--
To add non XDoclet generator parameters, create a file named
hibernate-generator-params-Person.xml
containing the additional parameters and place it in your merge dir.
-->
</generator>
<many-to-one
name="address"
class="javamxj.hibernate.association.one2one.Address"
cascade="all"
outer-join="auto"
update="true"
insert="true"
access="property"
column="fk_Address"
unique="true"
/>
cascade="all"
outer-join="auto"
update="true"
insert="true"
access="property"
column="fk_Address"
unique="true"
/>
· 注意:这里<many-to-one>上加上unique="true",表示限制一个Person有一个独有的Address。
· 然后同上面文章一样,生成映射文件,生成表,执行Demo,最后数据表中生成如下数据:
![](http://blog.csdn.net/images/blog_csdn_net/javamxj/111071/o_hib73.jpg)
![](http://blog.csdn.net/images/blog_csdn_net/javamxj/111071/o_hib74.jpg)
· t_person表中多了一个fk_Address外键,这个外键将t_person表和t_address表一一对应起来了。
Hibernate中的关联(Association)映射主要有三种:一对一关联,一对多(或多对一)关联,多对多关联。每种关联都可以分为单向和双向两种。
· 上面的 lazy="false"表示不采用延迟加载, inverse="false"表示主控方在Room端,这些属性都是XDoclet默认生成的,以后还会提到的。
上篇文章《
Eclipse快速上手Hibernate--5. 关联映射(一对一) 》已经说了一对一关联,这次谈谈一对多(或多对一)关联。至于环境设置,可以参考这个系列的前面几篇文章。
这篇文章主要是参考
《Hibernate入门》系列文章的第18-22小节。这里有两个类,一个是Room,一个是User。一个Room可以提供给多个User享用,这样就构成了一对多的关联。
1. 创建项目
· 新建一个Java项目:AssociationMapping,注意选中“创建单独的源文件夹和输出文件夹”,同时添加“用户库”:hibernate。
2. 编写类文件
· 新建一个类,包名:javamxj.hibernate.association.one2many,类名:Room。
Room.java
package javamxj.hibernate.association.one2many;import java.util.HashSet;import java.util.Set;/** * @hibernate.class table = "T_Room" */public class Room { private Long id; private String address; private Set users = new HashSet(); /** * @hibernate.id * column="ID" * generator-class="hilo" * unsaved-value="null" */ public Long getId() { return id; } public void setId(Long id) { this.id = id; } /** * @hibernate.property length = "24" */ public String getAddress() { return address; } public void setAddress(String address) { this.address = address; } /** * @hibernate.collection-one-to-many * class = "javamxj.hibernate.association.one2many.User" * @hibernate.collection-key * column = "Room_ID" * @hibernate.set * cascade = "all" * table = "T_User" */ public Set getUsers() { return users; } public void setUsers(Set users) { this.users = users; }}
· 在最后几行中指明了引用User类的方式,其中
@hibernate.collection-key 表明在T_User表定义了外键Room_ID。通过这个外键来反映一对多关系。
· 同样,在这个包下新建一个User类。
User.java
package javamxj.hibernate.association.one2many;/** * @hibernate.class table = "T_User" */public class User { private Long id; private String name; /** * @hibernate.id * column="ID" * generator-class="hilo" * unsaved-value="null" */ public Long getId() { return id; } public void setId(Long id) { this.id = id; } /** * @hibernate.property length = "24" */ public String getName() { return name; } public void setName(String name) { this.name = name; } }
3. 运行任务
· 复制《
Eclipse快速上手Hibernate--4. 继承映射(1)》文中的build.xml到项目根目录下。
· 双击“generate-hbm”任务,会发现在包中产生了Room.hbm.xml和User.hbm.xml文件,在src目录下会多了一个hibernate.cfg.xml文件,如果没有,按F5键刷新一下。
· 看看Room类的映射文件中的有关一对多关联部分:
<set
name="users"
name="users"
table="T_User"
lazy="false"
inverse="false"
cascade="all"
sort="unsorted"
>
<key
column="Room_ID"
>
</key>
<one-to-many
class="javamxj.hibernate.association.one2many.User"
/>
</set>
lazy="false"
inverse="false"
cascade="all"
sort="unsorted"
>
<key
column="Room_ID"
>
</key>
<one-to-many
class="javamxj.hibernate.association.one2many.User"
/>
</set>
· 上面的 lazy="false"表示不采用延迟加载, inverse="false"表示主控方在Room端,这些属性都是XDoclet默认生成的,以后还会提到的。
· 运行MySql服务器,然后双击“schemaexport”任务,在项目根目录下,会产生一个“schema-export.sql”文件。
· 切换到数据库中,会发现已经自动产生了数据表T_Room和T_User。
4. 测试程序
· 好了,在包javamxj.hibernate.association.one2one下新建一个Demo.java文件。
Demo.java
/* * Hibernate - 关联(Association)映射(一对多) * 创建日期 2005-4-27 * @author javamxj(分享java快乐) * @link Blog: htpp://blog.csdn.net/javamxj/ * htpp://javamxj.mblogger.cn */package javamxj.hibernate.association.one2many;import net.sf.hibernate.*;import net.sf.hibernate.cfg.*;public class Demo { public static void main(String[] args) throws HibernateException { User user1 = new User(); user1.setName("张三"); User user2 = new User(); user2.setName("李四"); User user3 = new User(); user3.setName("王二"); Room room1 = new Room(); room1.setAddress("科研007"); room1.getUsers().add(user1); room1.getUsers().add(user2); Room room2 = new Room(); room2.setAddress("销售001"); room2.getUsers().add(user3); SessionFactory sessionFactory = new Configuration().configure().buildSessionFactory(); Session session = sessionFactory.openSession(); Transaction tx = session.beginTransaction(); session.save(room1); session.save(room2); tx.commit(); session.close(); sessionFactory.close(); }}
· 运行这个类,数据表中生成如下数据:
![](http://blog.csdn.net/images/blog_csdn_net/javamxj/111071/o_hib82.jpg)
![](http://blog.csdn.net/images/blog_csdn_net/javamxj/111071/o_hib83.jpg)
· 同时,控制台输出如下:
![](http://blog.csdn.net/images/blog_csdn_net/javamxj/111071/o_hib81.jpg)
· 这里关联方向是单向,并且关联关系由Room对象维持的。它首先存储的是Room对象,然后存储Room对应的多个User,这时User表上的关联字段Room_ID是Null,最后Room对象将自己的ID值赋予到User表上的Room_ID,完成每个User更新(update)对Room自己的关联。
Hibernate执行这些操作一共用了8条语句,如果使关联关系由User对象维持的,那么后面的3条updata语句是可以不用的,下篇文章会谈到这一点的。
· 最后的项目结构如下:
![](http://blog.csdn.net/images/blog_csdn_net/javamxj/111071/o_hib84.jpg)
上篇文章《
Eclipse快速上手Hibernate--7. 关联映射(一对多) (1)》已经说了一对多的单向关联,这次还是用Room和User类来说明多对一的单向关联,只不过这次关联关系是由User对象维持的。
由于有了上篇文章的基础,只要做些修改就可以了。
· 修改Room类,仅仅是删除了关联User类的代码。
Room.java
package javamxj.hibernate.association.one2many;/** * @hibernate.class table = "T_Room" */public class Room { private Long id; private String address; /** * @hibernate.id * column="ID" * generator-class="hilo" * unsaved-value="null" */ public Long getId() { return id; } public void setId(Long id) { this.id = id; } /** * @hibernate.property length = "24" */ public String getAddress() { return address; } public void setAddress(String address) { this.address = address; } }
· 同样修改User类,也是仅仅添加了关联Room类的代码。
User.java
package javamxj.hibernate.association.one2many;/** * @hibernate.class table = "T_User" */public class User { private Long id; private String name; private Room room; /** * @hibernate.id * column="ID" * generator-class="hilo" * unsaved-value="null" */ public Long getId() { return id; } public void setId(Long id) { this.id = id; } /** * @hibernate.property length = "24" */ public String getName() { return name; } public void setName(String name) { this.name = name; } /** * @hibernate.many-to-one * cascade="save-update" * column="Room_ID" */ public Room getRoom() { return room; } public void setRoom(Room room) { this.room = room; } }
· 在最后几行中指明了引用Room类的方式,其中
@hibernate.many-to-one 表明在T_User表定义了外键Room_ID。通过这个外键来反映多对一关系。
· 看看Room类的映射文件中的有关多对一关联部分:
<many-to-one
name="room"
name="room"
class="javamxj.hibernate.association.one2many.Room"
cascade="save-update"
outer-join="auto"
update="true"
insert="true"
access="property"
column="Room_ID"
/>
· 这次级联关系是 cascade= " save-update ", 当删除多的一方中的一个对象时,其所关联的一的一方并不能同时被删除,因为它有可能还关联着多的一方中的其它对象,所以这次不用 cascade= " all " 了。
cascade="save-update"
outer-join="auto"
update="true"
insert="true"
access="property"
column="Room_ID"
/>
· 这次级联关系是 cascade= " save-update ", 当删除多的一方中的一个对象时,其所关联的一的一方并不能同时被删除,因为它有可能还关联着多的一方中的其它对象,所以这次不用 cascade= " all " 了。
· 修改Demo.java文件,User通过级联来更新Room。
Demo.java
/* * Hibernate - 关联(Association)映射(一对多) * 创建日期 2005-4-27 * @author javamxj(分享java快乐) * @link Blog: htpp://blog.csdn.net/javamxj/ * htpp://javamxj.mblogger.cn */package javamxj.hibernate.association.one2many;import net.sf.hibernate.*;import net.sf.hibernate.cfg.*;public class Demo { public static void main(String[] args) throws HibernateException { Room room1 = new Room(); room1.setAddress("科研007"); Room room2 = new Room(); room2.setAddress("销售001"); User user1 = new User(); user1.setName("张三"); user1.setRoom(room1); User user2 = new User(); user2.setName("李四"); user2.setRoom(room1); User user3 = new User(); user3.setName("王二"); user3.setRoom(room2); SessionFactory sf= new Configuration().configure().buildSessionFactory(); Session session = sf.openSession(); Transaction tx = session.beginTransaction(); session.save(user1); session.save(user2); session.save(user3); tx.commit(); session.close(); sf.close(); }}
· 然后同上面文章一样,生成映射文件,生成表,执行Demo,最后数据表中生成如下数据:
![](http://blog.csdn.net/images/blog_csdn_net/javamxj/111071/o_hib85.jpg)
![](http://blog.csdn.net/images/blog_csdn_net/javamxj/111071/o_hib86.jpg)
· 同时,控制台输出如下:
![](http://blog.csdn.net/images/blog_csdn_net/javamxj/111071/o_hib87.jpg)
可以看到,多对一关联相比一对多关联,只用了5条语句就完成了相同的操作结果。由于关联关系由User对象维持的,每个User都对应至一个Room。它首先存储的是Room对象,在存储User对象时,因为User已经知道Room的存在,所以可以通过关联字段Room_ID将User对象对Room对象的关系一并存储在T_User表中了。
这两篇文章谈论的都是单向关联,如果Room类和User类存在双向关联,又该如何呢?下篇文章见。
前面两篇文章《
关联映射(一对多) (1)》、《
关联映射(一对多) (2)》分别谈了“单向一对多关系”与“单向多对一关系”,双向一对多关系就是二者的组合。为了更好地提高执行效率,需要将“多”的一端设为主控方,就是将关联关系的维护工作交给“多”的一端。
以《
关联映射(一对多) (2)》为基础,只要改动一下Room类即可。
· 修改Room类,仅仅是添加了关联User类的代码。
Room.java
package javamxj.hibernate.association.one2many;import java.util.HashSet;import java.util.Set;/** * @hibernate.class table = "T_Room" */public class Room { private Long id; private String address; private Set users = new HashSet(); /** * @hibernate.id * column="ID" * generator-class="hilo" * unsaved-value="null" */ public Long getId() { return id; } public void setId(Long id) { this.id = id; } /** * @hibernate.property length = "24" */ public String getAddress() { return address; } public void setAddress(String address) { this.address = address; } /** * @hibernate.collection-one-to-many * class = "javamxj.hibernate.association.one2many.User" * @hibernate.collection-key * column = "Room_ID" * @hibernate.set * cascade = "all" * table = "T_User" * inverse = "true" */ public Set getUsers() { return users; } public void setUsers(Set users) { this.users = users; }}
这个类同《
关联映射(一对多) (1)》中的Room类几乎完全一样,有一点不同在于多了
inverse = "true",这样就将Room设置成了被控方,而将主控方交给了User。
· 然后同上面文章一样,生成映射文件,生成表,执行Demo,最后数据表中生成同上篇文章中相同的数据。
· 也可以修改Demo.java文件,让User设置关联关系,Room通过级联来更新User。
Demo.java
/* * Hibernate - 关联(Association)映射(一对多) * 创建日期 2005-4-27 * @author javamxj(分享java快乐) * @link Blog: htpp://blog.csdn.net/javamxj/ * htpp://javamxj.mblogger.cn */package javamxj.hibernate.association.one2many;import net.sf.hibernate.*;import net.sf.hibernate.cfg.*;public class Demo { public static void main(String[] args) throws HibernateException { Room room1 = new Room(); room1.setAddress("科研007"); Room room2 = new Room(); room2.setAddress("销售001"); User user1 = new User(); user1.setName("张三"); user1.setRoom(room1); User user2 = new User(); user2.setName("李四"); user2.setRoom(room1); User user3 = new User(); user3.setName("王二"); user3.setRoom(room2); room1.getUsers().add(user1); room1.getUsers().add(user2); room2.getUsers().add(user3); SessionFactory sf= new Configuration().configure().buildSessionFactory(); Session session = sf.openSession(); Transaction tx = session.beginTransaction(); session.save(room1); session.save(room2); tx.commit(); session.close(); sf.close(); }}
Hibernate中的关联(Association)映射主要有三种:一对一关联,一对多(或多对一)关联,多对多关联。每种关联都可以分为单向和双向两种。
前面文章已经说了一对一关联和一对多(或多对一)关联,这次谈谈多对多关联。至于环境设置,可以参考这个系列的前面几篇文章。
这里有两个类,一个是Student,一个是Course。一个学生可以选择多个课程,而一个课程也可以被多个学生选择,这样就构成了多对多的关联。这个关联是单向的,由Student控制的。
1. 创建项目
· 新建一个Java项目:AssociationMapping,注意选中“创建单独的源文件夹和输出文件夹”,同时添加“用户库”:hibernate。
2. 编写类文件
· 新建一个类,包名:javamxj.hibernate.association.many2many,类名:Student。
Student.java
package javamxj.hibernate.association.many2many;import java.util.HashSet;import java.util.Set;/** * @hibernate.class table = "T_Student" */public class Student { private Long id; private Set courses=new HashSet(); private String name; public Student() {} public Student(String name) { this.name = name; } /** * @hibernate.id * column="ID" * generator-class="hilo" * unsaved-value="null" */ public Long getId() {return id;} public void setId(Long id) {this.id = id;} /** * @hibernate.set * table="students_in_course" * cascade="save-update" * @hibernate.collection-many-to-many * column="fk_course" * class="javamxj.hibernate.association.many2many.Course" * @hibernate.collection-key * column="fk_student" */ public Set getCourses() {return courses;} public void setCourses(Set courses) {this.courses = courses;} /** * @hibernate.property length = "16" */ public String getName() {return name;} public void setName(String name) {this.name = name;}}
· 重点看看有关多对多关联的XDoclet标记。
· 同样,在这个包下新建一个Course类。
Course.java
package javamxj.hibernate.association.many2many;/** * @hibernate.class table = "T_Course" */public class Course { private Long id; private String description; public Course(){} public Course(String description) { this.description = description; } /** * @hibernate.id * column="ID" * generator-class="hilo" * unsaved-value="null" */ public Long getId() {return id;} public void setId(Long id) {this.id = id;} /** * @hibernate.property * length = "40" */ public String getDescription() {return description;} public void setDescription(String description) {this.description = description;}}
3. 运行任务
· 复制《
Eclipse快速上手Hibernate--4. 继承映射(1)》文中的build.xml到项目根目录下。
· 双击“generate-hbm”任务,会发现在包中产生了Student.hbm.xml和Course.hbm.xml文件,在src目录下会多了一个hibernate.cfg.xml文件,如果没有,按F5键刷新一下。
· 看看Student类的映射文件中的有关多对多关联部分:
<set
name="courses"
table="students_in_course"
lazy="false"
inverse="false"
cascade="save-update"
sort="unsorted"
>
<key
column="fk_student"
>
</key>
<many-to-many
class="javamxj.hibernate.association.many2many.Course"
column="fk_course"
outer-join="auto"
/>
</set>
· 上面的 lazy="false"表示不采用延迟加载, inverse="false"表示主控方在Student端。
name="courses"
table="students_in_course"
lazy="false"
inverse="false"
cascade="save-update"
sort="unsorted"
>
<key
column="fk_student"
>
</key>
<many-to-many
class="javamxj.hibernate.association.many2many.Course"
column="fk_course"
outer-join="auto"
/>
</set>
· 上面的 lazy="false"表示不采用延迟加载, inverse="false"表示主控方在Student端。
· 这里没有直接建立Student类和Course类的多对多关联,而是通过一个中介类来反映多对多的关联,这个中介类分别与Student类和Course类构成多对一关联,这个中介类映射的表通过
table="students_in_course" 获得。这个表有两个字段,分别是
fk_student、fk_course 。
· 运行MySql服务器,然后双击“schemaexport”任务,在项目根目录下,会产生一个“schema-export.sql”文件。
· 切换到数据库中,会发现已经自动产生了数据表T_Student、T_Course 和 students_in_course。
4. 测试程序
· 好了,在包javamxj.hibernate.association.one2one下新建一个Demo.java文件。
Demo.java
/* * Hibernate - 关联(Association)映射(多对多) * 创建日期 2005-5-1 * @author javamxj(分享java快乐) * @link Blog: htpp://blog.csdn.net/javamxj/ * htpp://javamxj.mblogger.cn */package javamxj.hibernate.association.many2many;import net.sf.hibernate.HibernateException;import net.sf.hibernate.Session;import net.sf.hibernate.SessionFactory;import net.sf.hibernate.Transaction;import net.sf.hibernate.cfg.Configuration;public class Demo { public static void main(String[] args) throws HibernateException { Student s1 = new Student("张三"); Student s2 = new Student("李四"); Course c1 = new Course("计算机"); Course c2 = new Course("英语"); Course c3 = new Course("航模活动"); Course c4 = new Course("数学"); s1.getCourses().add(c1); s1.getCourses().add(c2); s2.getCourses().add(c2); s2.getCourses().add(c3); s2.getCourses().add(c4); SessionFactory sf= new Configuration().configure().buildSessionFactory(); Session session = sf.openSession(); Transaction tx = session.beginTransaction(); session.save(s1); session.save(s2); tx.commit(); session.close(); sf.close(); } }
· 运行这个类,数据表中生成如下数据:
![](http://blog.csdn.net/images/blog_csdn_net/javamxj/111071/o_hib91.jpg)
![](http://blog.csdn.net/images/blog_csdn_net/javamxj/111071/o_hib92.jpg)
![](http://blog.csdn.net/images/blog_csdn_net/javamxj/111071/o_hib93.jpg)
· 最后的项目结构如下:
![](http://blog.csdn.net/images/blog_csdn_net/javamxj/111071/o_hib94.jpg)