爪哇咖啡館

          我為J狂

            BlogJava :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理 ::
            11 隨筆 :: 2 文章 :: 39 評論 :: 0 Trackbacks

          通過Hibernate項目中提供的幾個命令行工具(他們也被當作項目的一部分不斷得到維護),還有XDoclet,Middlegen和AndroMDA內置的對Hibernate的支持,可以在幾個不同的環境(SQL,java代碼,xml映射文件)中進行相互轉換(roundtrip)。

          Hibernate的主發行包中附帶了最重要的工具(甚至在Hibernate內部也可以快速調用這個工具):

          • 從映射文件到DDL schema的生成器(也就是SchemaExport和hbm2ddl)

          Hibernate項目直接提供的其他工具在一個單獨的發行包中發布,Hibernate Extensions。這個發行包包含了下列任務的工具:

          • 從映射文件到Java源代碼的生成器(也就是CodeGenerator,hbm2java)

          • 從已編譯的Java類或者帶有XDoclet標記的Java源代碼生成映射文件(它們是MapGenerator,class2hbm)

          實際上Hibernate Extensions里面還有一個工具:ddl2hbm。但是它已經被廢棄了,已經不再被維護了。Middlegen完成了同樣的任務,并且更加出色。

          對Hibernate提供支持的第三方工具有:

          • Middlegen (從現有的數據庫schema中生成映射文件)

          • AndroMDA ( 使用MDA思想(Model-Driven Architecture ,模型驅動體系)的代碼生成器,它從UML圖和其XML/XMI等價形式中生成持久化類的代碼)

          這些第三方工具沒有在這篇指南中說明。請查閱Hibernate 網站得到關于它們目前的情況。(Hibernate主發行包中有關于整個網站的快照)

          15.1. Schema 生成器(Schema Generation)

          可以從你的映射文件使用一個命令行工具生成DDL。在Hibernate主發行包的hibernate-x.x.x/bin目錄下有一個批處理文件。

          生成的schema包含有對實體和集合類表的完整性引用約束(主鍵和外鍵)。涉及到的標示符生成器所需的表和sequence也會同時生成。

          在使用這個工具的時候,你必須 通過hibernate.dialet屬性指定一個SQL方言(Dialet)。

          15.1.1. 對schema定制化(Customizing the schema)

          很多Hibernate映射元素定義了一個可選的length屬性。你可以通過這個屬性設置字段的長度。 (如果是Or, for numeric/decimal data types, the precision.)

          有些tag接受not-null屬性(用來在表字段上生成NOT NULL約束)和unique屬性(用來在表字段上生成UNIQUE約束)。

          有些tag接受index屬性,用來指定字段的index名字。unique-key屬性可以對成組的字段指定一個組合鍵約束(unit key constraint)。目前,unique-key屬性指定的值并不會被當作這個約束的名字,它們只是在用來在映射文件內部用作區分的。

          示例:

          <property name="foo" type="string" length="64" not-null="true"/>
          <many-to-one name="bar" foreign-key="fk_foo_bar" not-null="true"/>
          <element column="serial_number" type="long" not-null="true" unique="true"/>

          另外,這些元素還接受<column>子元素。在定義跨越多字段的類型時特別有用。

          <property name="foo" type="string">
          <column name="foo" length="64" not-null="true" sql-type="text"/>
          </property>
          <property name="bar" type="my.customtypes.MultiColumnType"/>
          <column name="fee" not-null="true" index="bar_idx"/>
          <column name="fi" not-null="true" index="bar_idx"/>
          <column name="fo" not-null="true" index="bar_idx"/>
          </property>

          sql-type屬性允許用戶覆蓋默認的Hibernate類型到SQL數據類型的映射。

          check屬性允許用戶指定一個約束檢查。

          <property name="foo" type="integer">
          <column name="foo" check="foo > 10"/>
          </property>
          <class name="Foo" table="foos" check="bar < 100.0">
          ...
          <property name="bar" type="float"/>
          </class>

          表 15.1. Summary

          屬性(Attribute) 值(Values) 解釋(Interpretation)
          length 數字 字段長度/小數點精度
          not-null true|false 指明字段是否應該是非空的
          unique true|false 指明是否該字段具有惟一約束
          index index_name 指明一個(多字段)的索引(index)的名字
          unique-key unique_key_name 指明多字段惟一約束的名字(參見上面的說明)
          foreign-key foreign_key_name 指明一個外鍵的名字,它是為關聯生成的。
          sql-type column_type 覆蓋默認的字段類型(只能用于<column>屬性)
          check SQL 表達式 對字段或表加入SQL約束檢查

          15.1.2. 運行該工具

          SchemaExport工具把DDL腳本寫到標準輸出,同時/或者執行DDL語句。

          java -cp hibernate_classpaths net.sf.hibernate.tool.hbm2ddl.SchemaExport options mapping_files

          表 15.2. SchemaExport命令行選項

          選項 說明
          --quiet 不要把腳本輸出到stdout
          --drop 只進行drop tables的步驟
          --text 不執行在數據庫中運行的步驟
          --output=my_schema.ddl 把輸出的ddl腳本輸出到一個文件
          --config=hibernate.cfg.xml 從XML文件讀入Hibernate配置
          --properties=hibernate.properties 從文件讀入數據庫屬性
          --format 把腳本中的SQL語句對齊和美化
          --delimiter=x 為腳本設置行結束符

          你甚至可以在你的應用程序中嵌入SchemaExport工具:

          Configuration cfg = ....;
          new SchemaExport(cfg).create(false, true);

          15.1.3. 屬性(Properties)

          可以通過如下方式指定數據庫屬性:

          • 通過-D<property>系統參數

          • 在hibernate.properties文件中

          • 位于一個其它名字的properties文件中,然后用 --properties參數指定

          所需的參數包括:

          表 15.3. SchemaExport 連接屬性

          屬性名 說明
          hibernate.connection.driver_class jdbc driver class
          hibernate.connection.url jdbc url
          hibernate.connection.username database user
          hibernate.connection.password user password
          hibernate.dialect 方言(dialect)

          15.1.4. 使用Ant(Using Ant)

          你可以在你的Ant build腳本中調用SchemaExport:

          <target name="schemaexport">
          <taskdef name="schemaexport"
          classname="net.sf.hibernate.tool.hbm2ddl.SchemaExportTask"
          classpathref="class.path"/>
          <schemaexport
          properties="hibernate.properties"
          quiet="no"
          text="no"
          drop="no"
          delimiter=";"
          output="schema-export.sql">
          <fileset dir="src">
          <include name="**/*.hbm.xml"/>
          </fileset>
          </schemaexport>
          </target>

          15.1.5. 對schema的增量更新(Incremental schema updates)

          SchemaUpdate工具對已存在的schema采用"增量"方式進行更新。注意SchemaUpdate嚴重依賴于JDBC metadata API,所以它并非對所有JDBC驅動都有效。

          java -cp hibernate_classpaths net.sf.hibernate.tool.hbm2ddl.SchemaUpdate options mapping_files

          表 15.4. SchemaUpdate命令行選項

          選項 說明
          --quiet 不要把腳本輸出到stdout
          --properties=hibernate.properties 從指定文件讀入數據庫屬性

          你可以在你的應用程序中嵌入SchemaUpdate工具:

          Configuration cfg = ....;
          new SchemaUpdate(cfg).execute(false);

          15.1.6. 用Ant來增量更新schema(Using Ant for incremental schema updates)

          你可以在Ant腳本中調用SchemaUpdate:

          <target name="schemaupdate">
          <taskdef name="schemaupdate"
          classname="net.sf.hibernate.tool.hbm2ddl.SchemaUpdateTask"
          classpathref="class.path"/>
          <schemaupdate
          properties="hibernate.properties"
          quiet="no">
          <fileset dir="src">
          <include name="**/*.hbm.xml"/>
          </fileset>
          </schemaupdate>
          </target>

          15.2. 代碼生成(Code Generation)

          Hibernate代碼生成器可以用來為Hibernate映射文件生成Java實現類的骨架。這個工具在Hibernate Extensions發行包中提供(需要單獨下載)。

          hbm2java解析映射文件,生成可工作的Java源代碼文件。使用hbm2java,你可以“只”提供.hbm文件,不用擔心要去手工編寫Java文件。

          java -cp hibernate_classpaths net.sf.hibernate.tool.hbm2java.CodeGenerator options mapping_files

          表 15.5. 代碼生成器命令行選項

          選項 說明
          --output=output_dir 生成代碼輸出的根目錄
          --config=config_file 可選的hvm2java配置文件

          15.2.1. 配置文件(可選)

          配置文件提供了配置生成源代碼的多個"渲染器(renders)"的途徑,也可以聲明在全局范圍生效的<meta>屬性。詳情請參見<meta>屬性的部分。

          <codegen>
          <meta attribute="implements">codegen.test.IAuditable</meta>
          <generate renderer="net.sf.hibernate.tool.hbm2java.BasicRenderer"/>
          <generate
          package="autofinders.only"
          suffix="Finder"
          renderer="net.sf.hibernate.tool.hbm2java.FinderRenderer"/>
          </codegen>

          這個配置文件聲明了一個全局的meta(元)屬性“implements”,指定了兩個渲染器,默認渲染器(BadicRender)和生成Finder(參見下面的“基本Finder 生成器”)的渲染器。

          定義第二個渲染器需要一個包名和后綴屬性。

          包名屬性指定生成后的源代碼應該保存的位置,覆蓋在.hbm文件中指定的包范圍。

          后綴屬性指定生成的文件的后綴。比如說,如果有一個Foo.java文件,應該變成FooFinder.java。

          也可以通過在<generate>元素上增加<param>屬性來傳遞特別的參數到渲染器去。

          hbm2java目前支持一個這樣的參數,名字是generate-concrete-empty-classes來通知BasicRender對你所有的類都只生成空的具體類來繼承它們。下列config.xml演示了這個功能

                      <codegen>
          <generate prefix="Base" renderer="net.sf.hibernate.tool.hbm2java.BasicRenderer"/>
          <generate renderer="net.sf.hibernate.tool.hbm2java.BasicRenderer">
          <param name="generate-concrete-empty-classes">true</param>
          <param name="baseclass-prefix">Base</param>
          </generate>
          </codegen>

          注意,這個config.xml定義了兩個渲染器。一個生成Base類,第二個只生成空的具體類。

          15.2.2. meta屬性

          <meta>標簽時對hbm.xml文件進行的簡單注解,工具可以用這個位置來保存/閱讀和Hibernate內核不是直接相關的一些信息。

          你可以用<meta>標簽來告訴hbm2java只生成"protectd"

          下面的例子:

          <class name="Person">
          <meta attribute="class-description">
          Javadoc for the Person class
          @author Frodo
          </meta>
          <meta attribute="implements">IAuditable</meta>
          <id name="id" type="long">
          <meta attribute="scope-set">protected</meta>
          <generator class="increment"/>
          </id>
          <property name="name" type="string">
          <meta attribute="field-description">The name of the person</meta>
          </property>
          </class>

          會生成類似下面的輸出(為了有助于理解,節選部分代碼)。注意Javadoc注釋和聲明成protected的set方法:

          // default package
          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;
          /**
          *         Javadoc for the Person class
          *         @author Frodo
          *
          */
          public class Person implements Serializable, IAuditable {
          /** identifier field */
          public Long id;
          /** nullable persistent field */
          public String name;
          /** full constructor */
          public Person(java.lang.String name) {
          this.name = name;
          }
          /** default constructor */
          public Person() {
          }
          public java.lang.Long getId() {
          return this.id;
          }
          protected void setId(java.lang.Long id) {
          this.id = id;
          }
          /**
          * The name of the person
          */
          public java.lang.String getName() {
          return this.name;
          }
          public void setName(java.lang.String name) {
          this.name = name;
          }
          }

          表 15.6. 支持的meta標簽

          屬性 說明
          class-description 插入到類的javadoc說明去
          field-description 插入到field/property的javadoc說明去
          interface 如果是true,生成interface而非class
          implements 類要實現的接口
          extends 類要繼承的超類(若是subclass,則忽略該屬性)
          generated-class 重新指定要生成的類名
          scope-class class的scope
          scope-set set方法的scope
          scope-get get方法的scope
          scope-field 實際屬性字段(field)的scope
          use-in-tostring 在toString()中包含此屬性
          implement-equals 在這個類中包含equals()和hashCode()方法
          use-in-equals 在equals()和hashCode() 方法中包含此屬性
          bound 為屬性增加propertyChangeListener支持
          constrained 為屬性增加vetoChangeListener支持
          gen-property 如果是false,不會生成屬性(謹慎使用)
          property-type 覆蓋屬性的默認值.如果值是標簽,則指定一個具體的類型而非Object(Use this with any tag's to specify the concrete type instead of just Object.)
          class-code 在類的最后會插入的額外代碼
          extra-import 在所有的import后面會插入的額外的import
          finder-method 參見下面的"Basic finder generator"
          session-method 參見下面的"Basic finder generator"

          通過<meta>標簽定義的屬性在一個hbm.xml文件中是默認"繼承"的。

          這究竟是什么意思?如果你希望你所有的類都實現IAuditable接口,那么你只需要加一個<meta attribute="implements">IAuditable</meta> 在你hml.xml文件的開頭,就在<hibernate-mapping>后面。現在所有在hbm.xml文件中定義的類都會實現IAuditable了?。ǔ四切┮蔡貏e指定了"implements"元屬性的類,因為本地指定的元標簽總是會覆蓋任何繼承的元標簽)。

          注意,這條規則對所有 的<meta>標簽都有效。也就是說它可以用來指定所有的字段都被聲明成protected的,而非默認的private。這可以通過在<class>后面<meta attribute="scope-field">protected</meta>指定,那么這個類所有的field都會變成protected。

          如果你不想讓<meta>標簽繼承,你可以簡單的在標簽屬性上指明inherit="false",比如<meta attribute="scope-class" inherit="false">public abstract</meta>,這樣"class-scope"就只會對當前類起作用,不會對其子類生效。

          15.2.3. 基本的finder生成器(Basic finder generator)

          目前可以讓hbm2java為Hibernate屬性生成基本的finder。這需要在hbm.xml文件中做兩件事情。

          首先是要標記出你希望生成finder的字段。你可以通過在property標簽中的meta 塊來定義:

          <property name="name" column="name" type="string">
          <meta attribute="finder-method">findByName</meta>
          </property>

          find方法的名字就是meta標簽中間的文字。

          第二件事是為hbm2java建立下面格式的配置文件:

          <codegen>
          <generate renderer="net.sf.hibernate.tool.hbm2java.BasicRenderer"/>
          <generate suffix="Finder" renderer="net.sf.hibernate.tool.hbm2java.FinderRenderer"/>
          </codegen>

          然后用參數去調用:hbm2java --config=xxx.xml,xxx.xml就是你剛才創建的配置文件的名字。

          有個可選的參數,作為一個在class級別的meta標簽,格式如下:

          <meta attribute="session-method">
          com.whatever.SessionTable.getSessionTable().getSession();
          </meta>

          他是用來管理你如何使用Thread Local Session模式(在Hibernate 網站的Design Patterns部分有文檔)得到session的。

          15.2.4. 基于Velocity的渲染器/生成器(Velocity based renderer/generator)

          目前可以使用velocity作為渲染機制的一個替代方案。下面的config.xml文件顯示了如果配置hbm2java來使用velocity渲染器。

              <codegen>
          <generate renderer="net.sf.hibernate.tool.hbm2java.VelocityRenderer">
          <param name="template">pojo.vm</param>
          </generate>
          </codegen>

          名為template的參數是指向你希望你使用velocity macro文件的資源路徑。這個文件必須在hbm2java的classpath中。所以要記住把pojo.vm所在的路徑加入到你ant任務或者shell腳本中去。(默認的位置是./tools/src/velocity)

          注意,當前的pojo.vm只生成java beans最基本的部分。他還沒有默認的渲染器那么完整,也沒有那么多功能——特別是大部分meta標簽還不支持。

          15.3. 映射文件生成器(Mapping File Generation)

          映射文件的骨架可以從編譯過的持久化類中使用MapGenerator工具生成。這工具是Hibernate Extensions發行包的一部分。

          Hibernate映射生成器提供了從編譯過的類中產生映射的機制。他使用Java反射來查找屬性( properties),然后使用啟發式算法來從屬性類型猜測合適的映射。生成出來的映射文件之應該看作是后續工作的起點。沒有辦法在沒有用戶修正的情況下生成完整的Hibernate映射。但是,這個工具還是替你做了很多非?,嵥楹吐闊┑墓ぷ?。

          類一個一個地加入到映射去。如果工具認為某個類不是Hibernate可持久化( persistable)的,就會把這些類剔除。

          判斷是否是Hibernate可持久化( persistable)的原則是:

          • 必定不是一個原始類型

          • 必定不是一個數組

          • 必定不是一個接口

          • 必定不是一個內部類

          • 必定有一個默認的無參數的構造方法。

          注意,接口和內部類實際上是可以通過Hibernate持久化的,但是一般來說用戶不會使用。

          對已經發現的類,MapGenerator會重復回溯到超類鏈條上去,以盡可能的把Hibernate可持久化的超類加入到對同一個數據庫表的映射去。如果回溯過程中某個類出現了有個屬性在下列備選UID名字(candidate UID names)名單中,回溯就會停止。

          默認的備選UID屬性名有:uid, UID, id, ID, key, KEY, pk, PK。

          如果類中有兩個方法,一個是setter,一個是getter,并且setter的單參數的屬性和getter的無參數返回值得類型相同,并且setter返回void,就認為發現了一個屬性。并且,setter的名字必須以set字符串開始,getter的名字必須以get開始,或者以is開始并且屬性類型是boolean。在上面的情況發生時,get和set之后的名字還必須匹配。這個匹配就是屬性的名字,然后如果第二個字母是小寫的話,會把其首字母變成小寫。

          用來決定每個屬性的數據庫類型的規則如下:

          1. 如果Java類型是Hibernate.basic(),則屬性是該類型的一個普通字段。

          2. 對于hibernate.type.Type特定類型和PersistentEnum來說,也會使用一個普通字段。

          3. 如果屬性類型是一個數組,那么會使用一個Hibernate數組,并且MapGenerator試圖反映數組元素的類型。(attempts to reflect on the array element type.)

          4. 如果屬性是java.util.List,java.util.Map或者java.util.Set,會使用對應的Hibernate類型,但是MapGenerator不能對這些類型進行進一步處理了。

          5. 如果屬性的類型不是上面任何一種,MapGeneraotr把決定數據庫類型的步驟留待所有的類都被處理之后再來做。在那時候,如果類在上面描述過的超類搜索過程中被發現了,這個屬性會被認為是一個many-to-one的關聯。如果類有人和屬性,它則是一個組件(component)。否則它就是可序列化的(serializable),或者不是可持久化的。

          15.3.1. 運行此工具

          這個工具會把XML映射寫入到標準輸出或者/并且到一個文件中去。

          在調用這個工具的時候,你必須把你編譯過的類放到classpath中去。

          java -cp hibernate_and_your_class_classpaths net.sf.hibernate.tool.class2hbm.MapGenerator options and classnames

          有兩種操作模式:命令行或者交互式。

          交互式模式當你使用一個惟一的命令行參數--interact的時候啟動。這個模式提供一個命令控制臺。你可以用uid=XXX命令設置每個類的UID屬性的名字,XXX就是UID屬性名。其他可用的命令就是類名的全限定名,或者“done”命令用來輸出XML,并且結束。

          在命令行模式下,下面的參數選項和所需處理的類的全限定名可以相互間隔使用。大多數選項會使用多次,每個只影響其后出現的類。

          表 15.7. MapGenerator命令行選項

          選項 說明
          --quiet 不把O-R 映射輸出到stdout
          --setUID=uid 設置備選UID名單
          --addUID=uid 在備選UID名單前面增加一個新的uid
          --select=mode 對后面的classes使用select選擇的模式(mode)(比如, distinct 或者all)
          --depth=<small-int> 限制后面的類的組件數據遞歸層數
          --output=my_mapping.xml 把O-R 映射輸出到一個文件
          full.class.Name 把這個類加入到映射中
          --abstract=full.class.Name 參見下面的說明

          abstract開關指定本工具忽略特定的超類,所以它的繼承數上的類不會被映射到一個大表中去。比如,我們來看下面的類繼承樹:

          Animal-->Mammal-->Human

          Animal-->Mammal-->Marsupial-->Kangaroo

          如果不使用--abstract開關,Animal的所有子類都會被放到一個巨大的表中去,包含所有類的所有屬性,還有一個用于分辨子類的字段。如果Mammal被標記成abstract,Human和Marsupial會被映射到不同的<class>聲明,并且會有各自單獨的表。Kangaroo仍然會被認為是Marsupial的子類,除非Marsupial也標記為anstract的。

          posted on 2007-04-23 20:13 哲藤峰子 閱讀(1727) 評論(2)  編輯  收藏

          評論

          # re: hbm2工具箱指南 2007-04-25 23:16 海藍
          @哲藤峰子

          請問你確實是在用這幾個工具嗎?就我在hibernate.org上看到的信息,這幾個工具是用于Hibernate 2的;為Hibernate 3.x重新開發的是Hibernate Tools......  回復  更多評論
            

          # re: hbm2工具箱指南 2013-03-01 15:37 未來城市
          很強大  回復  更多評論
            


          只有注冊用戶登錄后才能發表評論。


          網站導航:
           
          主站蜘蛛池模板: 柏乡县| 武宁县| 万宁市| 琼中| 应城市| 巨鹿县| 房山区| 界首市| 霸州市| 嘉祥县| 洛川县| 当雄县| 阳江市| 嵩明县| 西林县| 毕节市| 蓬安县| 当雄县| 鹤壁市| 莱芜市| 祁东县| 辽源市| 元谋县| 永康市| 赤峰市| 沈丘县| 三明市| 时尚| 海口市| 上饶市| 渭源县| 庆安县| 建水县| 门源| 汉川市| 郴州市| 曲靖市| 文化| 靖安县| 青河县| 喀什市|