对象建模还是E-R建模
良好的模型对于高效的开发高性能的应用系统是至关重要的。每个团队在进行设计时都必须得进行选择:是用纯 OOD/OOA 的思想进行对象建模或者用面向关系数据的思想进行 E-R 建模,这是个艰难的抉择!选择其中的每一种都会导致不同的开发流程,其中各有利弊。
下面是使用对象建模的一些工具和方法步骤:
流程:类图 —>Java 源代 - à ( 加 Xdoclet)- à 映射文件( .hbm.xml ) - à 数据库表 - à 物理数据模型(如果需要的话)
1、 先用对象建模工具(例如 rose )把类图设计好。在该步骤中要注意把各个类之间的关系(如一对一、一对多、多对多)搞清楚,这使得下一步添加 Xdoclet 时工作量比较小。
2、 用对象建模工具从设计好的类图中导出 Java 源代码。
3、 导出源代码后就可在源代码中添加 Xdoclet 标签了,这些标签用于生成 Hibernate 的映射文件。在添加 Xdoclet 标签时要注意的是:要把 Xdoclet 标签加在每个属性的 getter ()方法之前,如果只在属性前加标签生成映射文件时就会报错。
举个例子 , 有一个人的实体类,我们在加 Xdoclet 时要特别注意,不要只加在属性之前,而是要加在每个属性的 getter ()方法之前,事实上可以不在属性之前加 Xdoclet 标签,如下所示例子中有一个 Set 类型的 address 属性,元素是 Address 对象(例子没有给出),假设一个人有多个地址,这是一个一对多的关系,在配置一对多和多对多关系时有几点要注意:
import java.io.Serializable;
import java.util.Set;
import java.util.HashSet;
/**
* @hibernate .class
* table="Tperson"
*
*/
public class Person implements Serializable {
private Long personId ;
private String name ;
private int age ;
private Set address = new HashSet(); // 在这一定要实例化 address 对象
// 我们应该在这加 Xdoclet
/**
* 年龄
* @hibernate .property
* type="int"
* column="age"
*/
public int getAge() {
return age ;
}
public void setAge( int age) {
this . age = age;
}
/**
* 用户 ID
* @hibernate .id
* generator="native"
* type="java.lang.Long"
* column="personId"
*/
public Long getPersonId() {
return personId ;
}
public void setPersonId(Long personId) {
this . personId = personId;
}
/**
* 用户姓名
* @hibernate .property
* type="java.lang.String"
* column="name"
* length="32"
* not - null="true"
*/
public String getName() {
return name ;
}
public void setName(String name) {
this . name = name;
}
/**
* 用户地址
* @hibernate .set
* table - "Taddress"
* class="Address"
*
* @hibernate .collection - key
* column="personId"
*
* 注意下面是 collection - one - to - many 而不是 one - to - many
* 对于多对多关系也是这样 collection - many - to - many
* @hibernate .collection - one - to - many
* class="Person"
*/
public Set getAddress() {
return address ;
}
public void setAddress(Set address) {
this . address = address;
}
}
加完了这些 Xdoclet 我们就可以用工具生成映射文件了。一般用得较多的 Xdoclet 的 Hibernate 标签有 :
@hibernate .class
@hibernate .id
@hibernate .property
@hibernate .set
@hibernate.many-to-one
以上只给出了一些经常用的标记,大家在开发时可参考 Xdoclet 手册。
4、 在 Myeclipse project 的 properties 窗口,选择左侧的 “MyEclipse-XDoclet” , “Add Standard...” , “Choose an entry” 这儿选择 “Standard Hibernate” 。如下图:右键电击你的工程,然后选择属性,你就会看到这个图。然后选择 Myeclipse 选项就会看到其中有一个子选项 Xdoclet ,点击 Xdoclet 出现如下界面,然后点击 Add Standard 按钮,选择其中的 Standard Hibernate ,我们可以看到, Xdoclet 支持很多技术的代码生成。
5、 右键点击工程根目录,选择 Myeclipse 选项的 Run Xdoclet ,这样就可以生成映射文件了生成的映射文件默认情况下是和你的 POJO 在同一目录下。(在这我只举了用 Myeclipse 工具生成映射文件,你也可以用其他方式生成,可选工具: Xdoclet—1.2.3( 支持 Hibernate3) 的 Ant 构建,具体配置请查阅相关资料)
6 、这一步要从映射文件生成数据库表。下面写一个测试类来生成数据库表,同时也一定程度上验证了我们的映射文件的配置文件是否正确,如果不正确,那么在生成数据库表时就会发生错误。
import java.io.File;
import java.util.List;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.HibernateException;
import org.hibernate.cfg.Configuration;
import junit.framework.TestCase;
public class TestHibernate extends TestCase {
protected Session session ;
public TestHibernate(String s) {
super (s);
}
protected void setUp() throws Exception {
super .setUp();
try {
Configuration config = new Configuration().configure( new File( "C://hibernate.cfg.xml" ));
SessionFactory factory = config.buildSessionFactory();
session = factory.openSession();
} catch (HibernateException e) {
e.printStackTrace();
}
}
protected void tearDown() throws Exception {
super .tearDown();
try {
session .close();
} catch (HibernateException e) {
e.printStackTrace();
}
}
public void testInsert() {
Transaction tx = null ;
try {
tx = session .beginTransaction();
Course course = new Course();
course.setCourseName( "computer" );
course.setDescription( " 计算 ” );
session .save(course);
session .flush();
tx.commit();
} catch (HibernateException e) {
e.printStackTrace();
fail (e.getMessage());
if (tx != null ) {
try {
tx.rollback();
} catch (HibernateException err) {
err.printStackTrace();
}
}
}
}
Hibernate 配置文件 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.url" > jdbc:mysql://localhost:3306/webstudy </ property >
< property name = "dialect" > org.hibernate.dialect.MySQLDialect </ property >
< property name = "connection.password" > root </ property >
< property name = "connection.driver_class" > com.mysql.jdbc.Driver </ property >
< property name = "hibernate.show_sql" > True </ property >
< property name = "hibernate.jdbc.batch_size" > 25 </ property >
< property name = "hibernate.jdbc.fatch_size" > 25 </ property >
< property name = "myeclipse.connection.profile" > MySQL </ property >
注意在这加上下面这一行:可选值: update , create , create-drop ; Hibernate 在加载该配置文件时会自动检测数据库表是否存在。如果设为 update ,如果数据库表不存在,则 Hibernate 会使用 SchemaExport 工具导出该表的定义然后创建该表。
< property name = "hibernate.hbm2ddl.auto" > update </ property >
< mapping resource = "Person.hbm.xml" />
</ session-factory >
</ hibernate-configuration >
(可选工具: Hibernate Synchronizer Eclipse 插件(这个工具支持正向工程和反向工程))
7、 数据库表自动创建完毕,单元测试顺利通过。
8 、日后如果对 Java 代码进行重构时,如果修改量不大我们可以手动去修改映射文件和数据库表的定义以达到三者之间的同步;而如果重构范围很大,我们完全可以重复以上的过程来达到三者同步的目的。
下面来总结一下我对面向对象建模的一些看法:
<1> 优点:完全采用 OOA/OOD 的思想,完全以 Java 代码为中心进行开发
<2> 缺点:手工添加 Xdoclet 工作量大,而且容易出错,并且要配置好一些关键性的东西,否则 Hibernate 的性能会很差。
下面是使用 E-R 建模的一些工具和方法步骤:
流程:物理数据模型 - à 数据库表 - à 映射文件( .hbm.xml ) - à Java 源代码
1、 用 E-R 建模工具(如 Power Designer 或者 Erwin )把物理数据模型建好
2、 用这些工具导出数据库表的定义,然后生成数据库表
3、 表生成后我们可以用 Middlegen 来生成映射文件, Middlegen 有一个专门的 Hibernate 的工具 Middlegen—Hibernate-r5 ,它依赖于 Ant (也有个 eclipse 插件),我们就用它来生成映射文件。下载了该工具后首先要修改 config/database 下面的 mysql.xml 文件,如果你用的是其他的数据库,则修改对应的 xml 文件,它支持多种数据库,修改后要把 mysql 的 JDBC 驱动程序加入 CLASSPATH 。
<property name="database.script.file" value="${src.dir}/sql/${name}-mysql.sql"/>
<property name="database.driver.file" value="${lib.dir}/mysql-connector-java-5.0.3-bin.jar"/>
<property name="database.driver.classpath" value="${database.driver.file}"/>
<property name="database.driver" value="com.mysql.jdbc.Driver"/>
<property name="database.url" value="jdbc:mysql://localhost/webstudy"/>
<property name="database.userid" value="root"/>
<property name="database.password" value="root"/>
<property name="database.schema" value=""/>
<property name="database.catalog" value=""/>
<property name="jboss.datasource.mapping" value="mySQL"/>
上面的一些参数你可以根据实际情况进行修改。
然后修改根目录下的 build.xml 文件的开始部分,指定使用 mysql.xml 配置文件。
<!DOCTYPE project [
<!ENTITY database SYSTEM "file:./config/database/mysql.xml">
]>
为了在映射文件中生成 Xdoclet ,我们找到 Middlegen 任务的子任务 Hibernate 部分:
<hibernate
destination="${build.gen-src.dir}"
package="${name}.hibernate"
genXDocletTags="false"
genIntergratedCompositeKeys="false"
javaTypeMapper="middlegen.plugins.hibernate.HibernateJavaTypeMapper"
/>
其中 destination 是生成的映射文件的目录,你可以自己修改到合适的路径
Package 属性你指定你的类的包名, genXDocletTags 是是否在映射文件中产生 Xdoclet ,如果为 true ,则在映射文件中会加人 Xdoclet ,生成 Java 源代码时这些 Xdoclet 也会被抽取到 Java 源代码中。
指定好以上参数后我们就可以运行 build.xml 文件了,你要先搭建好 Ant 构建环境。到达 build.xml 文件所在的目录后从命令行输入 ant , middlegen 就会自动运行了,如下图:
我们可以改变两个实体的关系和方向,默认它会生成双向关系。点击每个实体可以修改它的一些配置。修改好后点击 Generate 就可以产生 Hibernate 映 射文件了,全部生产在你之前指定的目录下。查看它生成的文件我们会发现它生成的映射文件并不完美,它把那些多对多关系的交叉表也生成了,而且在生成的映射 文件中的多对多的关系配置还有点问题,但是用工具生成比手工编写出错的几率要小得多,而且效率也要高得多,在项目的初期我们可以使用这个工具大规模的生成 映射文件,在中、后期如果我们对 Java 文件或者映射文件进行重构后我们就不应该使用 Middlegen 了,而是通过正向工程来同步三者。
4、 对上一步生成的映射文件做好修改后我们就可以生成 Java 源文件了。我们可以用 Hibernate Synchronizer Eclipse 插件来生成,也可以直接用 Myeclipse 生成(如果你已经装了的话)。如果使用 Myeclipse 生成 Java 源代码,我们只需要右键点击映射文件,然后选择 Myeclipse 选项的子选项 Gen POJO ,生成的 Java 源代码默认和映射文件在同一目录下。如果装了 Hibernate Synchronizer Eclipse 插件,右键点击映射文件你会看到 Synchronizer 选项,生成的方式与 Myeclipse 基本上一样。
5、 生成的 Java 源代码和上面用面向对象方法时我们在 Java 源代码中加入 Xdoclet 后基本上一样的。需要注意的是如果我们需要对数据库表字段进行修改,我们不再使用 Middlegen 了,否则它重新生成的映射文件会把我们已经修改的映射文件给覆盖掉,而我们应该用面向对象的方式从 Java 源代码到映射文件在到数据库表,或者我们完全可以以映射文件中的 Xdoclet 为中心,向上生成 Java 源代码,向下生成数据库表,这些根据你的喜好,两者没有太大的区别。
下面我来总结一下我对 E-R 建模的一些看法:
优点:工具生成代码效率高,而且不易出错,可用于项目初期大规模生成映射文件,在日常的项目中是用得最多的。
缺点:工具并不是万能的,生成的代码并不尽善尽美。而且在用 Middlegen 生成的那一步中,如果表很多时在它的那个图形用户界面显示出来的实体将惨不忍睹,密密麻麻,可能你没有耐心去调整那些实体的关系了。
综上所诉,目前我们在开发面向对象应用时还不能完全抛弃 E-R 建模,因为目前还没有哪个工具足够强大从对象模型到 Java 源代码在到映射文件和数据库表的自动完美的构建,所以我们在开发项目时应该根据实际情况进行选择,比如说如果公司有一批精通数据库建模的精英队伍,那我们就要充分利用这些宝贵的资源,而不是一味的采取面向对象的思想去开发。