利用hibernateTools里的相關工具類,使得java實體類(POJO)、hbm映射文件、數據庫表(Schema)之間可以相互轉化。也就是說,只要有其中一樣,就可以通過各種途徑得到其它兩樣。
如果手里已經有了其中一樣東西,要想最快建立起應用的途徑自然是通過它來生成其它兩樣了。不過,我想在這里討論的是那種從無到有,從想法到實現的那種建立全新應用的情況。那么,自然而然就會有一個問題:“從哪里開始?”。實體類?hbm?數據庫表?先應該建立哪一個,再通過它生成其它兩個?
這個問題我覺得應該從Hibernate框架的產生的初忠來考慮:為了解決“面向對象模型”與“關系模型”之間的“阻抗不匹配”。簡而言之,就是說在我們的類圖和E-R關系圖中各元素的對應關系很難把握,而且容易讓人產生概念的混淆,如“每一個數據庫表對應一個實體類”等錯誤想法,很容易讓人在設計實體時不知不覺扔掉很多面向對象模型的優秀思想。其實并不能說哪一個模型是錯,只是因為他們描述問題的方向不同。那么,Hibernate框架就是把這兩個模型“映射”了起來,讓程序員可以在面向對象的世界里完成對數據庫的查詢,而不必關心底層的數據庫表的結構。
說了那么多,直接了當地講,我不贊成“先建立數據表,再通過這個數據表生成POJO和hbm文件”這種方案。道理很簡單:如果先就去考慮數據庫,那么我們隨后的設計勢必會受到這個數據庫的影響,不利于精確地描述我們的應用,Hibernate框架的好處也就體現不出來了(先就把數據庫搞定了還要Hibernate來干什么),生成的POJO不用說——內容多半很別扭——因為你企圖從一個非面向對象的框框里硬抽象出面向對象模型來(也許你會認為這是可以通過經驗來避免的,是的,確實是,不過你不覺得這樣一來工作復雜化了嗎?要考慮的東西增多了)。
面向對象模型是用來精確而自然地描述問題的,這是我的看法,它提供了包含、繼承等等機制,幾乎能把這個世界上的所有事物之間的關系精確地描述出來——它好比一門語言——怎么方便你就怎么說。那么,先數據庫再POJO的做法就好比是先規定了你只能用哪些詞語之后讓你說話,而先POJO再數據庫就好比是讓你隨便說隨便發揮了,自然后者要好得多。
從軟件工程的角度講,需求——用例——實體這樣一趟走下來,POJO出現在數據庫前面是很自然的,在OOA階段就考慮數據庫是很不可取的做法(絕對一點講——是錯誤的)。
OK,剩下的POJO和hbm文件之間應該先生成哪個呢?我覺得先生成誰都無所謂,都不會對我們的工程產生不利影響了。
hbm文件作為POJO和數據庫之間的橋梁,從它入手的話會有一舉兩得的感覺,全是干凈的XML文件。當然,貌似利用xDoclet標簽在我們寫POJO代碼的時候自動生成hbm也是很不錯的感覺,這個下次再討論吧,現在給出一個完整可用而且最簡單的hbm生成POJO和Schema的示例:
準備:
下載ant工具,我用的是apache-ant-1.7.0,當然,你要會用ant,怎么使用請參考別處,這里不介紹了。
下載hibernate-3.2.1.ga.zip,以及HibernateTools-3.2.0.beta9a.zip,這兩個壓縮包在hibernate官網上有: http://www.hibernate.org/6.html
數據庫的jdbc驅動程序,本例使用mysql,驅動程序為mysql-connector-java-5.0.4。
布置實驗場所:
建立“test”文件夾(其實叫什么都無所謂),再在test文件夾下建立4個文件夾:config、java、schema、lib。
解壓hibernate-3.2.1.ga.zip,把里面的hibernate-3.2文件夾放在你建立的lib文件夾里面。
解壓HibernateTools-3.2.0.beta9a.zip,找出hibernate-tools.jar,位置在:
\HibernateTools-3.2.0.beta9a\plugins\org.hibernate.eclipse_3.2.0.beta9a\lib\tools;
在與hibernate-tools.jar同樣的位置下找出freemarker.jar;
把hibernate-tools.jar和freemarker.jar都放入你建立的lib文件夾里。
最后把數據庫驅動程序:mysql-connector-java-5.0.4-bin.jar也放進lib文件夾里,
這樣,所需要的類資源都準備好了。
進入config文件夾,首先寫hibernate config文件,文件名:hibernate.cfg.xml:
<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
????????? "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
????????? "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
?<session-factory>
??<property name="connection.username">root</property>
??<property name="connection.password">XXXXXXXXXX</property><!--Your DB password here.-->
??<property name="connection.url">jdbc:mysql://localhost:3306/courseChoosing</property>
??<property name="connection.driver_class">com.mysql.jdbc.Driver</property>
??<property name="dialect">org.hibernate.dialect.MySQLDialect</property>
??<mapping resource="Student.hbm.xml" />
??<mapping resource="Course.hbm.xml" />
?</session-factory>
</hibernate-configuration>
以上代碼不用過多解釋,就是hibernate的配置文件,其中有連接數據庫的重要信息。只是connection.password屬性注意修改成你自己的密碼就行了。那兩個mapping元素是本例要創建的兩個hbm文件,待會兒我們再實際地創建它,現在不用管。
好了,hibernate配置文件寫好了之后,我們現在該討論一下我們將要進行的這個例子的與“業務”相關的話題了:
很簡單——我就拿“學生選課”這件事來做這個例子,具體描述是這樣的:“一門課可以被多個學生選,一個學生也可以選擇多門課。”很顯然,這是一個多對多關系。畫出實體類圖應該是這樣的(PowerDesigner12):
?
也就是說,在“學生”這個類中會有一個set,保存了這個學生所選的所有的課;同時,在“課程”這個類中也會有一個set,保存了所有要上這門課的學生。
弄清楚了類圖之后,讓我們用hbm文件來分別描述這兩個類:
還是在config文件夾下,建立Course.hbm.xml和Student.hbm.xml,
Course.hbm.xml的內容如下:
<?xml version = "1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package = "courseChoosing">
?<class name = "Course" table = "course">
??<id name = "id" column = "id" type = "long">
???<generator class = "native" />
??</id>
??<property name = "name" type = "string" length = "50" />
??<property name = "credit" type = "integer" />
??<property name = "totalClasses" type = "integer" />
??<set name = "students" table = "courseChoosing" inverse = "true">
???<key column = "courseId" />
???<many-to-many class = "Student" column = "studentId" />
??</set>
?</class>
</hibernate-mapping>
Student.hbm.xml的內容如下:
<?xml version = "1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package = "courseChoosing">
?<class name = "Student" table = "student">
??<id name = "id" column = "id" type = "long">
???<generator class = "native" />
??</id>
??<property name = "stuNo" type = "string" length = "10" />
??<property name = "name" type = "string" length = "20" />
??<property name = "gender" type = "character" />
??<set name = "courses" table = "courseChoosing" inverse = "false">
???<key column = "studentId" />
???<many-to-many class = "Course" column = "courseId" />
??</set>
?</class>
</hibernate-mapping>
這兩個文件是純粹的hbm文件描述實體類的方式,看上去很簡潔,層次很清晰。需要仔細看明白的是其中的那個set元素:
name屬性是這個set的名字,也就是最后生成的java代碼中的這個set的名字;table屬性是這個set對應的數據庫表的名字,由于這個是多對多關系,所以需要另外建立一個表來存儲學生和課程之間的選擇關系,不過這種細節不用管,hibernatetools會做好一切。最重要的是那個inverse屬性,它決定了多對多關系的兩邊到底由誰來管理雙方的關系數據。inverse設為“true”的一方將不負責維護雙方的關系數據,本例中考慮實際情況,決定讓“學生”類來維護這個選課關系(因為從來只有學生選課或退出選課,而沒有課選學生或課踢除學生的情況),于是將Course類里的set的inverse屬性設為“true”,Student里的inverse為“false”。順便提一句,如果不指明inverse屬性,那么默認為false。many-to-many元素說明了他們之間的關系,class屬性指明了當前set中對象的類型,column屬性指明了關系表(courseChoosing)中的外碼名。
到此為止,與業務相關的東西已經描述完畢,剩下的就是編寫ant腳本來實際生成ddl和java文件了。
在test文件夾下,建立build.xml文件,其內容如下:
<?xml version="1.0"?>
<project name = "test" default = "hbm2java">
?<property name = "configuration-files.dir" value = "config" />
?<property name = "java.code.dir" value = "java" />
?<property name = "schema.dir" value = "schema" />
?<property name = "lib.dir" value = "lib" />
?<property name = "hibernate3.dir" value = "${lib.dir}/hibernate-3.2" />
?<path id = "hibernate3.path">
??<pathelement location = "${hibernate3.dir}/hibernate3.jar" />
??<fileset dir = "${hibernate3.dir}">
???<include name = "**/*.jar" />
??</fileset>
?</path>
?<path id = "mysql.jdbc.driver.path">
??<pathelement location = "${lib.dir}/mysql-connector-java-5.0.4-bin.jar" />
?</path>
?<path id = "hibernate-tools.path">
??<pathelement location = "${lib.dir}/hibernate-tools.jar" />
?</path>
?<path id = "freemarker.path">
??<pathelement location = "${lib.dir}/freemarker.jar" />
?</path>
?<path id = "all-in-one.path">
??<path refid = "hibernate3.path" />
??<path refid = "mysql.jdbc.driver.path" />
??<path refid = "hibernate-tools.path" />
??<path refid = "freemarker.path" />
??<pathelement location = "${configuration-files.dir}" />
?</path>
?<target name = "hbm2java">
??<taskdef name = "hbm2java" classname = "org.hibernate.tool.ant.HibernateToolTask" classpathref = "all-in-one.path" />
??<hbm2java destdir = "${java.code.dir}">
???<configuration configurationfile = "${configuration-files.dir}/hibernate.cfg.xml" />
???<hbm2java jdk5 = "true" />
??</hbm2java>
?</target>
?<target name = "hbm2ddl">
??<taskdef name = "hbm2ddl" classname = "org.hibernate.tool.ant.HibernateToolTask" classpathref = "all-in-one.path" />
??<hbm2ddl destdir = "${schema.dir}">
???<configuration configurationfile = "${configuration-files.dir}/hibernate.cfg.xml" />
???<hbm2ddl export="true" console="false" create="true" update="false" drop="false" outputfilename="courseChoosing.sql" />
??</hbm2ddl>
?</target>
</project>
很平常的ant腳本,需要注意的是那兩個特殊的任務:hbm2java和hbm2ddl,這兩個任務是hibernatetools里帶的,需要定義出來,就不多說了。
好了,安裝好ant之后就可以運行這個腳本了,生成java文件:
?
?
生成數據庫表:
?
大功告成了,欣賞一下結果:
在java文件夾中生成的java文件代碼:
Course.java文件:
package courseChoosing;
// Generated 2007-3-7 15:38:42 by Hibernate Tools 3.2.0.b9
import java.util.HashSet;
import java.util.Set;
/**
?* Course generated by hbm2java
?*/
public class Course? implements java.io.Serializable {
???? private long id;
???? private String name;
???? private Integer credit;
???? private Integer totalClasses;
???? private Set<Student> students = new HashSet<Student>(0);
??? public Course() {
??? }
??? public Course(String name, Integer credit, Integer totalClasses, Set<Student> students) {
?????? this.name = name;
?????? this.credit = credit;
?????? this.totalClasses = totalClasses;
?????? this.students = students;
??? }
??
??? public long getId() {
??????? return this.id;
??? }
???
??? public void setId(long id) {
??????? this.id = id;
??? }
??? public String getName() {
??????? return this.name;
??? }
???
??? public void setName(String name) {
??????? this.name = name;
??? }
??? public Integer getCredit() {
??????? return this.credit;
??? }
???
??? public void setCredit(Integer credit) {
??????? this.credit = credit;
??? }
??? public Integer getTotalClasses() {
??????? return this.totalClasses;
??? }
???
??? public void setTotalClasses(Integer totalClasses) {
??????? this.totalClasses = totalClasses;
??? }
??? public Set<Student> getStudents() {
??????? return this.students;
??? }
???
??? public void setStudents(Set<Student> students) {
??????? this.students = students;
??? }
?
}
Student.java文件中的內容:
package courseChoosing;
// Generated 2007-3-7 15:38:42 by Hibernate Tools 3.2.0.b9
import java.util.HashSet;
import java.util.Set;
/**
?* Student generated by hbm2java
?*/
public class Student? implements java.io.Serializable {
???? private long id;
???? private String stuNo;
???? private String name;
???? private Character gender;
???? private Set<Course> courses = new HashSet<Course>(0);
??? public Student() {
??? }
??? public Student(String stuNo, String name, Character gender, Set<Course> courses) {
?????? this.stuNo = stuNo;
?????? this.name = name;
?????? this.gender = gender;
?????? this.courses = courses;
??? }
??
??? public long getId() {
??????? return this.id;
??? }
???
??? public void setId(long id) {
??????? this.id = id;
??? }
??? public String getStuNo() {
??????? return this.stuNo;
??? }
???
??? public void setStuNo(String stuNo) {
??????? this.stuNo = stuNo;
??? }
??? public String getName() {
??????? return this.name;
??? }
???
??? public void setName(String name) {
??????? this.name = name;
??? }
??? public Character getGender() {
??????? return this.gender;
??? }
???
??? public void setGender(Character gender) {
??????? this.gender = gender;
??? }
??? public Set<Course> getCourses() {
??????? return this.courses;
??? }
???
??? public void setCourses(Set<Course> courses) {
??????? this.courses = courses;
??? }
?
}
?
schema文件夾中生成的courseChoosing.sql文件內容:
create table course (id bigint not null auto_increment, name varchar(50), credit integer, totalClasses integer, primary key (id));
create table courseChoosing (studentId bigint not null, courseId bigint not null, primary key (studentId, courseId));
create table student (id bigint not null auto_increment, stuNo varchar(10), name varchar(20), gender char(1), primary key (id));
alter table courseChoosing add index FK42CD624F924EFB30 (courseId), add constraint FK42CD624F924EFB30 foreign key (courseId) references course (id);
alter table courseChoosing add index FK42CD624F417DBA12 (studentId), add constraint FK42CD624F417DBA12 foreign key (studentId) references student (id);
生成的數據庫表(MySQL Administrator):
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
