选择显示字体大小

用hbm2java生成hibernate类

hibernate 是流行的处理对象/关系持久化及查询的开源工具。 在hibernate 中,数据库表与pojo(“plain old java objects”,“普通java对象”)类之间的映射是由一组xml 映射文件来配置的。  hbm2java 是把映射文件转化成pojo 类的代码生成器。它是hibernate tools 子项目的一部分, 可以从独立的hibernate extension下载包中得到。

版权声明:任何获得matrix授权的网站,转载时请务必保留以下作者信息和链接
作者:john;smart;czyczy(作者的blog:http://blog.matrix.org.cn/page/czyczy)
原文:http://www.onjava.com/pub/a/onjava/2005/12/14/hibernate-class-generation-with-hbm2java.html
译文:http://www.matrix.org.cn/resource/article/44/44248_hbm2java+hibernate.html
关键字:hbm2java;hibernate

对于管理hiberante 映射文件,现有多种策略, 如:
·        一切手工编写
·        把xdoclet标记放在你的java 类中, 让其生成相应的映射文件。
·        从sql 模式(schema)生成hibernate 映射文件和java类。
·        手工编写hibernate 映射文件, 并且从hibernate 映射生成java类和sql模式
·        基于给定的sql 模式,手工编写hibernate 映射文件,并利用hbm2java工具生成java类。

在本文中, 我们会着眼于上述方法中的最后那种方法。尽管这样的选择通常只是约略的尝试, 但此方法的确在多数情况下有许多优势:
·        hibernate 映射集中在映射文件中,而不是把这些信息散布在java源代码中,这使维护变得更加容易。在某些情况下,xdoclet annotation 不支持所有在hibernate映射模式中可用的功能,你还可通过映射获得更好的控制。
·        数据库模式可分开来维护,而不是从java 类或hibernate映射文件生成。这允许那些对java/hibernate不甚了解的数据库管理员(dba)对数据库细节(索引,表空间,表类型等)本身有更好的控制。

由映射文件生成java

这种方式下,hibernate映射文件主导着一切。所有的映射信息都集中在这些文件中, 就意味着不会在源代码中使用annotations。所有的持久化类都由hbm2java工具生成。之后,那些类就不能被修改。
此过程如图1所示。首先,你持有一组hibernate映射文件。你或许也需要一个hbm2java配置文件,通常称之为hbm2java.xml。利用这两个引子,hbm2java工具为每个hibernate映射文件生成一个或多个java类。hbm2java配置文件对类生成过程的优化是有用的。


图1.用hbm2java工具将hibernate映射生成java

        
一个简单类生成的例子

让我们从一个非常简单的例子开始。假设我们想映射一个book的简单数据库表,表结构定义如下:

column                   type                   modifiers
------------+-----------------------+-----------
book_id       character(32)             not null
book_title character varying(80) not null
book_isbn   character varying(20) not null


为了生成这个类, 我们可以使用以下的hiberante映射文件。注意怎样利用元属性(meta-attriute)来添加注释或优化类的生成。

<?xml version=&quot;1.0&quot;?>


<hibernate-mapping>

    <class name=&quot;book&quot; table=&quot;book&quot;>
        <meta attribute=&quot;class-description&quot;>
            a book business object.
            @author duke
        </meta>
        <id name=&quot;id&quot; type=&quot;string&quot; unsaved-value=&quot;null&quot; >
            <column name=&quot;book_id&quot; sql-type=&quot;char(32)&quot; not-null=&quot;true&quot;/>
            <generator class=&quot;uuid.hex&quot;/>
        </id>

        <property column=&quot;book_name&quot; name=&quot;name&quot;/>
        <property column=&quot;book_isbn&quot; name=&quot;isbn&quot;>
            <meta attribute=&quot;field-description&quot;/>
            the unique isbn code for this book.
            </meta>
        </property>
    </class>

</hibernate-mapping>


使用此映射文件,hbm2java会生成看起来象这样的类:
/**
* a book business object.
* @author duke
*/
public class book {

    private string id;
    private string name;
    private string isbn;

    public book() {
    }

    public string getid() {
        return id;
    }

    private void setid(string id) {
        this.id = id;
    }

    public string getname() {
        return name;
    }

    public void setname(string name) {
        this.name = name;
    }

    /**
     * the unique isbn code for this book.
     */
    public string getisbn() {
        return isbn;
    }

    public void setisbn(string isbn) {
        this.isbn = isbn;
    }
}
        

为实际项目生成类

实际上,hbm2java被设计成用来把hibernate映射文件转化成一组相应的java类。如果你想在实际的应用程序中使用这种方法,很显然,对于所有的hibernate映射文件一次性生成类会更为方便。最好的方法是把类生成结合进你的自动化构建过程中。
结合进ant构建过程中使用ant调用hbm2java是相当直接的。首先,你需要申明hbm2java任务(task)以便ant可以调用它:
  
     <taskdef name=&quot;hbm2java&quot;
                classname=&quot.net.sf.hibernate.tool.hbm2java.hbm2javatask&quot;
                classpathref=&quot;project.class.path&quot;/>

  
接着,你要用到这个任务。例如,通过写一个目标(target)将源目录中的所有*.hbm.xml文件生成源代码。假设${src.hibernate}表示含有hibernate映射文件的目录,${src.generated}就是你想放源代码的地方。这样ant任务看起来就象是:
       <target name=&quot;codegen&quot;
               description=&quot;generate java source code
                            from the hibernate mapping files&quot;>
         <hbm2java output=&quot;${source.generated}&quot;>
           <fileset dir=&quot;${src.hibernate}&quot;>
             <include name=&quot;**/*.hbm.xml&quot;/>
           </fileset>
         </hbm2java>
       </target>

  
用maven 1 定制构建过程

为结合进maven (  1.0)构建过程,你需要修改maven.xml文件。maven代码就存放在这个文件中。脚本(script)主要检查了hibernate映射文件自上次类生成后是否已被更改(使用uptodate 标记),如果没有,就调用此前所描述的ant中的hbm2java任务。这种情况下,我们做了以下的假设:
&middot;        hbm2java.xml配置文件应在src/hibernate目录中
&middot;        hibernate映射文件应在src/hibernate目录中
&middot;        在src/generated/src/java目录下生成java
  
<goal name=&quot;generate-hibernate-classes&quot;>
    <ant:echo message=&quot;hibernate class generation&quot;/>

    <fileset dir=&quot;${basedir}/src&quot; id=&quot;fileset.hbm.xml&quot;>
        <include name=&quot;**/*.hbm.xml&quot;/>
    </fileset>

    <uptodate property=&quot;hibernatebuild.uptodate&quot;
              targetfile=&quot;${maven.src.dir}/generated/hbm.jar&quot;>
       <srcfiles refid=&quot;fileset.hbm.xml&quot;/>
    </uptodate>

    <j:set var=&quot;buildhibernatefiles&quot;
           value=&quot;${hibernatebuild.uptodate}&quot;/>

    <j:choose>
        <j:when test=&quot;${buildhibernatefiles != null}&quot;>
              <ant:echo message=&quot;hibernate classes up to date&quot;/>
        </j:when>
        <j:otherwise>
              <ant:echo message=&quot;generating hibernate classes to src/java&quot;/>

              <ant:taskdef name=&quot;hbm2java&quot;
                           classname=&quot.net.sf.hibernate.tool.hbm2java.hbm2javatask&quot;
                           classpathref=&quot;maven.dependency.classpath&quot;/>

              <ant:hbm2java config=&quot;${maven.src.dir}/conf/hbm2java.xml&quot;
                            output=&quot;${maven.src.dir}/generated/src/java&quot; >
                  <ant:fileset dir=&quot;${maven.src.dir}/hibernate&quot;>
                      <ant:include name=&quot;**/*.hbm.xml&quot;/>
                  </ant:fileset>
              </ant:hbm2java>

              <ant:jar jarfile=&quot;${maven.src.dir}/generated/hbm.jar&quot;>
                  <fileset refid=&quot;fileset.hbm.xml&quot;/>
              </ant:jar>
        </j:otherwise>
    </j:choose>
</goal>
  

用maven 2 定制构建过程

若碰巧你正使用maven 2,事情就更简单一点了。把maven-antrun-plugin插件添加到pom.xml文件中,而不是在maven.xml文件中使用完整的goals属性(pre and post goals)。在此插件中的task那部分,你可以象上述那样直接调用ant 任务。
<project...>
  <modelversion>4.0.0</modelversion>
  ...
  <build>
    ...
    <plugins>
       <plugin>
          <artifactid>maven-antrun-plugin</artifactid>
          <executions>
            <execution>
              <phase>generate-sources</phase>
              <configuration>
                <tasks>
                  <taskdef name=&quot;hibernatetool&quot;
                           classname=&quot;org.hibernate.tool.ant.hibernatetooltask&quot;
                           classpathref=&quot;maven.dependency.classpath&quot;/>

                  <hbm2java output=&quot;src/generated&quot;>
                      <fileset dir=&quot;src/hibernate&quot;>
                          <include name=&quot;**/*.hbm.xml&quot;/>
                      </fileset>
                  </hbm2java>
                </tasks>
              </configuration>
              <goals>
                <goal>run</goal>
              </goals>
            </execution>
          </executions>
        </plugin>
     </plugins>
  </build>
</project>
  
        
hibernate 3中使用hbm2java

hbm2java 工具已经经受了hibernate 3 的考验。hbm2java任务与其它相似的任务一起,被集成进了新版hibernate 工具集中的hibernatetool任务(撰写此文时仍是alpha版)。ant任务需要在类路径(class path)中查找以下的.jar 文件:
&middot;        hibernate-tools.jar
&middot;        velocity-1.4.jar
&middot;        velocity-tools-generic-1.4.jar
&middot;        jtidy-r8-21122004.jar
&middot;        hibernate3.jar
&middot;        jdbc drivers

这样一来,ant任务就要作如下申明:
    <taskdef name=&quot;hibernatetool&quot;
        classname=&quot;org.hibernate.tool.ant.hibernatetooltask&quot;
        classpathref=&quot;maven.dependency.classpath&quot;/>


最后,你在hibernatetool 任务中调用hbm2java任务,做法如下:
  
    <taskdef name=&quot;hibernatetool&quot;
        classname=&quot;org.hibernate.tool.ant.hibernatetooltask&quot;
        classpathref=&quot;maven.dependency.classpath&quot;/>

    <hibernatetool destdir=&quot;src/main/generated/src/java&quot;>
        <configuration configurationfile=&quot;src/main/hibernate/hibernate.cfg.xml&quot;>
            <fileset dir=&quot;src/main/hibernate&quot;>
                <include name=&quot;**/*.hbm.xml&quot;/>
            </fileset>
        </configuration>

        <hbm2java />
    </hibernatetool>

  
注意:尽管hibernate 3版的工具是很有前途的,但它仍只是在alpha阶段,因此使用时务必小心为是。(译注:翻译此文时最新的hibernate版本是3.1.2,hibernate tools的版本是3.1 beta 4)

定制生成的domain类

现在你知道了怎样从hibernate映射生成java源代码, 那么下一步呢?
为了更加具体地讨论,我们将使用如图2 和3所描述的简单类模型。这个类模型表示employee数据库。每个employee赋予一country,讲一种或多种language。每个country 也有一组国际机场(airport)。


图2. 示例应用程序的uml类图


图3. 示例中所用的数据库模式

有时,你可能想添加域逻辑到domain类中。实际上,对多数人来说,生成java类的主要缺点是domain类变得相对被动,而且把业务逻辑方法加入生成的domain类中并不容易,就如所论证的那样使它们更不接近&ldquo;面向对象&ldquo;。对这问题并没有一个万能的解决方案,但我们在此描述了一些可能的方法。
        
把代码放入映射文件: class-code元属性(meta attribute)
对于简单的方法,你可以用class-code元属性来在hibernate映射文件中指定额外的java代码。例如,假设我们想在country和airports间建立双向关系。只要我们想增加airport属性到country 对象,我们就要确定在airport对象中相应地增加country属性。我们可以这么做:
  
    <class name=&quot;country&quot; table=&quot;country&quot; dynamic-update=&quot;true&quot;>
        <meta attribute=&quot;implement-equals&quot;>true</meta>
        <meta attribute=&quot;class-code&quot;>
            <!&#91;cdata&#91;
                /**
                 * add an airport to this country
                 */
                public void addairport(airport airport) {
                    airport.setcountry(this);
                    if (airports == null) {
                          airports = new java.util.hashset();
                    }
                    airports.add(airport);
                }

            &#93;&#93;>
        </meta>


        <id name=&quot;id&quot; type=&quot;long&quot; unsaved-value=&quot;null&quot; >
            <column name=&quot;cn_id&quot; not-null=&quot;true&quot;/>
            <generator class=&quot;increment&quot;/>
        </id>

           <property column=&quot;cn_code&quot; name=&quot;code&quot; type=&quot;string&quot;/>
           <property column=&quot;cn_name&quot; name=&quot;name&quot; type=&quot;string&quot;/>

          <set name=&quot;airports&quot; >
            <key column=&quot;cn_id&quot;/>
            <one-to-many class=&quot;airport&quot;/>
          </set>
    </class>
  

除了那些非常小的方法,这种做法并不是特别地令人满意:在xml文件里编写java代码的做法很容易出错而且难于维护。
使用sql表达式有时业务逻辑(特别地如果引入了聚合,求和,合计等运算)可能会更自然地用sql表达式来定义:
  
    <property name=&quot;ordertotal&quot; type=&quot;java.lang.double&quot;
              formula=&quot;(select sum(item.amount)
                        from item
                        where item.order_id = order_id)&quot; />

  
在多数情况下这是非常好的解决方案。但是,必须注意的是每次hibernate数据库加载对象时都会执行查询的动作,这可能会对性能造成影响。

使用基类
你也可以用generated-class元属性来定义基类,hbm2java会用这些元属性生成基类,这样你就可以在所生成基类的子类中自由地添加业务逻辑。例如,我们可以在country类上应用这种技术,就象下面所描述的:
  
    <class name=&quot;country&quot; table=&quot;country&quot; dynamic-update=&quot;true&quot;>
        <meta attribute=&quot;implement-equals&quot;>true</meta>
        <meta attribute=&quot;generated-class&quot;>countrybase</meta>
        <meta attribute=&quot;scope-field&quot;>protected</meta>

        <id name=&quot;id&quot; type=&quot;long&quot; unsaved-value=&quot;null&quot; >
            <column name=&quot;cn_id&quot; not-null=&quot;true&quot;/>
            <generator class=&quot;increment&quot;/>
        </id>

           <property column=&quot;cn_code&quot; name=&quot;code&quot; type=&quot;string&quot;/>
           <property column=&quot;cn_name&quot; name=&quot;name&quot; type=&quot;string&quot;/>

          <set name=&quot;airports&quot; >
            <key column=&quot;cn_id&quot;/>
            <one-to-many class=&quot;airport&quot;/>
          </set>
    </class>
  

hbm2java生成countrybase类,此类包含了所有在映射文件中描述的属性,getter,setter等。接着,你可以在country的派生类中自由地添加业务逻辑,这些会被hibernate使用并实例化,例如:
  
    public class country extends countrybase {
        /**
         * add an airport to this country
         */
        public void addairport(airport airport) {
                airport.setcountry(this);
                if (getairports() == null) {
                        setairports(new java.util.hashset());
                }
                getairports().add(airport);
        }
    }

  
包装(wrapper)或委派(delegate)模式(pattern)
对于更复杂的业务逻辑,你或许也想使用下列技术中的一种:
&middot;        你可以定义&ldquo;wrapper&rdquo;或&ldquo;delegate&rdquo;类,这些类含有作为属性的domain类,并且提供了指定域类额外的业务逻辑。
&middot;        你可能更喜欢&ldquo;服务(service)&rdquo;或&ldquo;外观(fa&ccedil;ade)&rdquo;方法,&ldquo;fa&ccedil;ade&rdquo;对象(如无状态的会话ejb)提供了一套相关的业务服务来操作domain对象。

结论
本文描述了我们用来管理hibernate映射的一种方法, 这在我们所特定的环境中工作得很好。 当然,还有许多别的方法。或许本文会给你的项目提供一些想法,但无论你做什么, 总要使用最适合你项目的方法。

资源
&middot;        hibernate
&middot;        hibernate tools
&middot;        ant
&middot;        hibernate ant tool
&middot;        maven

john ferguson smart从1991起涉足it行业, 99年开始从事j2ee的开发。


 


关键字 本文所属关键字

相关 与本文相关文章

分类 所有文章关键字导航

源码编程相关

Java   Asp   PHP   .Net   XML   C/C++   CGI   VB   Jsp   J2ee   J2se   J2me   EJB   Servlet   Tomcat   Resin   Struts   Weblogic   Eclipse   ANT   GUI   JMS   Web servise   IDEA   Webphere   Hibernate   Spring   Jboss   Applet   Swing   Socket   Javamail   Perl   Ajax   P2P   安全   模式   框架   测试   开源   游戏

SQL数据库相关

My-SQL   Ms-SQL   Access   DB2   Oracle   Sybase   SQLserver   索引   存储过程   加密   数据库   分页   视图  

手机无线相关

3G   Wap   CDMA   GRPS   GSM   IVR   彩信   短信   无线   增值业务

网页设计制作相关

HTML   CSS   网页配色   网页特效   Javascript   VBscript   Dreamweaver   Frontpage   JS   Web   网站设计

网站建设推广相关

建站经验   网站优化   网站排名   推广   Alexa

操作系统/服务器相关

Windows XP   Windows 2000   Windows 2003   Windows Me   Windows 9.x   Linux   UNIX   注册表   操作系统   服务器   应用服务器

图形图像多媒体相关

Photoshop   Fireworks   Flash   Coreldraw   Illustrator   Freehand   Photoimpact   多媒体   图形图像

标准 网站致力的规范

Valid CSS!

无不良内容,无不良广告,无恶意代码

Valid XHTML 1.0 Transitional

creativecommons