返回介绍

编制数据库 Schema

发布于 2025-04-21 21:42:11 字数 11155 浏览 0 评论 0 收藏 0

刚才真简单,对吧?根据映射来创建数据库表也差不多是这样,你会很愉快地学习下去。和代码生成一样,只要利用映射文件,几乎所有工作都做完了。剩下的就是设置和运行 schema 生成工具。

应该怎么做

第一步是我们在第 1 章间接提到的一些事情。我们必须告诉 Hibernate,我们要使用什么数据库,这样,Hibernate 才知道应该使用什么 SQL“方言”(dialect)。没错,SQL 是标准,但每种数据库系统在标准 SQL 基础上,还都有各自在某些方面的扩展,有一套会影响到实际应用的特定功能和限制。为了解决这一现实问题,Hibernate 提供了一组类来封装常见数据库环境的独特功能,这些类位于 org.hibernate.dialect 包中。你只需要告诉 Hibernate 想要使用哪一种数据库(如果你要使用的数据库是 Hibernate 目前尚未支持的,也可以自行实现必需的 SQL 方言)。

在我们的这个例子中,使用的是 HSQLDB 数据库,所以要用 HSQLDialect。配置 Hibernate 最简单的方法就是创建一个名为 hibernate.properties 的属性配置文件,再将它放在项目类路径的根目录中。在 src 目录的顶层创建这个文件,将例 2-4 的内容放进去。

例 2-4:设置 hibernate.properties 的内容

hibernate.dialect=org.hibernate.dialect.HSQLDialect

hibernate.connection.driver_class=org.hsqldb.jdbcDriver

hibernate.connection.url=jdbc:hsqldb:data/music

hibernate.connection.username=sa

hibernate.connection.password=

hibernate.connection.shutdown=true

除了设置要使用的 SQL 方言以外,这个属性配置文件也会告诉 Hibernate 如何使用封装在 HSQLDB 数据库 JAR 文件内的 JDBC 驱动程序来建立数据库的连接,而且数据应该放在 data 目录下名为 music 的数据库中。在经过第 1 章的实践以后,对用户名和空密码(事实上,所有都是这个值)应该都很熟悉了。最后,我们告诉 Hibernate,当处理完成后,应该显式关闭数据库连接,这是在嵌入模式下处理 HSQLDB 的一个 artifact。如果不关闭连接的话,当工具退出时,对数据库的修改就不一定会写入到数据库中,所以你的数据库模式总是莫名其妙地为空。

如前所述,你也可以使用 XML 格式来保存配置信息,但就此处的简单需求而言,这样做没有什么价值。我们将在第 3 章介绍 XML 格式的配置方法。

你也可以把.properties 文件存放在其他地方,并提供不同的文件名称,或者以完全不同的方式把这些设置属性传递给 Hibernate。但这里是 Hibernate 寻找配置文件的默认位置,因此这是个最方便的路径(或者,我猜想也是需要最少运行时配置的方法)。

我们也需要在 Ant 构建文件中加入一些新项,如例 2-5 所示,在 build.xml 文件末尾的</project>结束标签前增加了一些新的目标。

例 2-5:生成 schema 所需要的 Ant 构建文件

<!--Create our runtime subdirectories and copy resources into them-->

<target name="prepare"description="Sets up build structures">❶

<mkdir dir="${class.root}"/>

<!--Copy our property files and O/R mappings for use at runtime-->

<copy todir="${class.root}">

<fileset dir="${source.root}">

<include name="**/*.properties"/>

<include name="**/*.xml"/>❷

</fileset>

</copy>

</target>

<!--Generate the schemas for all mapping files in our class tree-->

<target name="schema"depends="prepare"❸

description="Generate DB schema from the O/R mapping files">

<hibernatetool destdir="${source.root}">

<configuration>

<fileset dir="${class.root}">

<include name="**/*.hbm.xml"/>

</fileset>

</configuration>

<hbm2ddl drop="yes"/>❹

</hibernatetool>

</target>

❶首先,我们加了一个 prepare 构建目标,以供其他构建目标使用,而不是从命令行直接调用。其用途是在必要时创建 classes 目录,以便将编译好的 Java 代码放在这个目录中,再把 src 目录中找到的任何.properties 文件和映射文件都复制到对应目录的 classes 层。这种层次式的复制是 Ant 相当棒的功能(使用特殊的“**/*”匹配模式),让我们可以定义和编辑源代码文件会使用到的相关资源,同时在运行时通过类加载器(class loader)来使用这些资源。

❷这一设置会让 Ant 复制所有找到的 XML 文件,而不仅仅是映射文档。虽然我们现在还不需要这样的配置文件,但以后当我们切换到基于 XML 的 Hibernate 配置文件时,这一设置就显得很重要了。

❸schema 构建目标需要依赖 prepare 构建目标,让它把映射文档复制到正确的位置以供运行时使用。它会用 hbm2ddl 模式来调用 Hibernate 工具,让它们为在 classes 目录中找到的任何映射文档生成相应的数据库模式(如前所述,在下一章我们使用功能更强大的 Hibernate XML 配置文件时,这样就会更简单些)。

❹可以为 schema 生成工具指定很多参数,以配置其工作方式。在这个例子中,我们告诉 schema 生成工具在根据映射文档生成新的数据表定义之前,先删除原来可能已经存在的(drop=yes)。有关这一配置和其他配置选项的更多细节,可以查阅 Hibernate Tools 参考手册。Hibernate 甚至可以检查现有的数据表,并尝试计算出如何修改 schema,才能反映出新映射文件的变化。

在添加了这些内容以后,就可以准备为我们的 TRACK 表生成数据库 schema 了。Hibernate 可以为实现我们的目标而完成许多奇特的操作,并井然有序地完成处理。我们只需要为一定的消息配置好日志处理,就可以很容易地观察到 Hibernate 进行的操作过程。为此,我们需要配置 Log4j,这是 Hibernate 所使用的日志处理环境。最简单的配置方法是直接在类路径下放一个 log4j.properties 文件。我们可以利用现有的 prepare target,在 Ant 复制 Hibernate 的.properties 文件时,顺便将 log4j.properties 文件从 src 目录复制到 classes 目录。

在 src 目录下创建一个名为 log4j.properties 的文件,内容如例 2-6 所示。(一种简单的做法就是从你下载的 Hibernate 发行包中的 doc/tutorial/src 目录将这个文件复制出来,因为该文件就是给 Hibernate 发行包所带的示例使用的。如果你自己输入,则可以跳过注释块的内容,它们只是介绍一些有用的日志功能的其他选项。)

例 2-6:log4j.properties 日志配置文件

###direct log messages to stdout###

log4j.appender.stdout=org.apache.log4j.ConsoleAppender

log4j.appender.stdout.Target=System.out

log4j.appender.stdout.layout=org.apache.log4j.PatternLayout

log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE}%5p%c{1}:%L-%m%n

###direct messages to file hibernate.log###

#log4j.appender.file=org.apache.log4j.FileAppender

#log4j.appender.file.File=hibernate.log

#log4j.appender.file.layout=org.apache.log4j.PatternLayout

#log4j.appender.file.layout.ConversionPattern=%d{ABSOLUTE}%5p%c{1}:%L-%m%n

###set log levels-for more verbose logging change'info'to'debug'###

log4j.rootLogger=warn, stdout

log4j.logger.org.hibernate=info

#log4j.logger.org.hibernate=debug

###log HQL query parser activity

#log4j.logger.org.hibernate.hql.ast.AST=debug

###log just the SQL

#log4j.logger.org.hibernate.SQL=debug

###log JDBC bind parameters###

log4j.logger.org.hibernate.type=info

#log4j.logger.org.hibernate.type=debug

###log schema export/update###

log4j.logger.org.hibernate.tool.hbm2ddl=debug

###log HQL parse trees

#log4j.logger.org.hibernate.hql=debug

###log cache activity###

#log4j.logger.org.hibernate.cache=debug

###log transaction activity

#log4j.logger.org.hibernate.transaction=debug

###log JDBC resource acquisition

#log4j.logger.org.hibernate.jdbc=debug

###enable the following line if you want to track down connection###

###leakages when using DriverManagerConnectionProvider###

#log4j.logger.org.hibernate.connection.DriverManagerConnectionProvider=trace

有了日志配置文件以后,你可能会想编辑 build.xml 中的 codegen 目标,使其也依赖于新的 prepare 目标。这样可以确保无论何时调用 codegen,都配置了日志处理,而且 Hibernate 配置也可以使用,消除了我们第一次使用它时的麻烦。

现在可以制作数据库模式了!在项目目录的命令行下,执行命令 ant prepare,接着再执行 ant schema。你会看到类似例 2-7 内容的输出,同时还会创建 classes 目录,并在其中生成了各种资源文件;再接着就会运行模式生成器(schema generator)。

例 2-7:使用 HSQLDB 的嵌入式数据库服务器来建立数据库模式

%ant prepare

Buildfile:build.xml

prepare:

[mkdir]Created dir:/Users/jim/svn/oreilly/hib_dev_2e/current/examples/

ch02/classes

[copy]Copying 3 files to/Users/jim/svn/oreilly/hib_dev_2e/current/

examples/ch02/classes

BUILD SUCCESSFUL

Total time:0 seconds

%ant schema

Buildfile:build.xml

prepare:

schema:

[hibernatetool]Executing Hibernate Tool with a Standard Configuration

[hibernatetool]1.task:hbm2ddl(Generates database schema)

[hibernatetool]22:38:21,858 INFO Environment:514-Hibernate 3.2.5

[hibernatetool]22:38:21,879 INFO Environment:532-loaded properties from reso

urce hibernate.properties:{hibernate.connection.username=sa, hibernate.connecti

on.password=****,hibernate.dialect=org.hibernate.dialect.HSQLDialect, hibernate.

connection.shutdown=true, hibernate.connection.url=jdbc:hsqldb:data/music, hibe

rnate.bytecode.use_reflection_optimizer=false, hibernate.connection.driver_class

=org.hsqldb.jdbcDriver}

[hibernatetool]22:38:21,897 INFO Environment:681-Bytecode provider name:cg

lib

[hibernatetool]22:38:21,930 INFO Environment:598-using JDK 1.4 java.sql.Time

stamp handling

[hibernatetool]22:38:22,108 INFO Configuration:299-Reading mappings from fil

e:/Users/jim/Documents/Work/OReilly/svn_hibernate/current/examples/ch02/classes/

com/oreilly/hh/data/Track.hbm.xml

[hibernatetool]22:38:22,669 INFO HbmBinder:300-Mapping class:com.oreilly.hh.

data.Track->TRACK

[hibernatetool]22:38:22,827 INFO Dialect:152-Using dialect:org.hibernate.di

alect.HSQLDialect

[hibernatetool]22:38:23,186 INFO SchemaExport:154-Running hbm2ddl schema exp

ort

[hibernatetool]22:38:23,194 DEBUG SchemaExport:170-import file not found:/im

port.sql

[hibernatetool]22:38:23,197 INFO SchemaExport:179-exporting generated schema

to database

[hibernatetool]22:38:23,232 INFO DriverManagerConnectionProvider:41-Using Hi

bernate built-in connection pool(not for production use!)

[hibernatetool]22:38:23,234 INFO DriverManagerConnectionProvider:42-Hibernat

e connection pool size:20

[hibernatetool]22:38:23,241 INFO DriverManagerConnectionProvider:45-autocomm

it mode:false

[hibernatetool]22:38:23,255 INFO DriverManagerConnectionProvider:80-using dr

iver:org.hsqldb.jdbcDriver at URL:jdbc:hsqldb:data/music

[hibernatetool]22:38:23,258 INFO DriverManagerConnectionProvider:86-connecti

on properties:{user=sa, password=****,shutdown=true}

[hibernatetool]drop table TRACK if exists;

[hibernatetool]22:38:23,945 DEBUG SchemaExport:303-drop table TRACK if exists;

[hibernatetool]create table TRACK(TRACK_ID integer generated by default as ide

ntity(start with 1),title varchar(255)not null, filePath varchar(255)not nul

l, playTime time, added date, volume smallint not null, primary key(TRACK_ID));

[hibernatetool]22:38:23,951 DEBUG SchemaExport:303-create table TRACK(TRACK_

ID integer generated by default as identity(start with 1),title varchar(255)n

ot null, filePath varchar(255)not null, playTime time, added date, volume small

int not null, primary key(TRACK_ID));

[hibernatetool]22:38:23,981 INFO SchemaExport:196-schema export complete

[hibernatetool]22:38:23,988 INFO DriverManagerConnectionProvider:147-cleanin

g up connection pool:jdbc:hsqldb:data/music

BUILD SUCCESSFUL

Total time:2 seconds

在模式导出(schema export)部分的末尾,你能够看到 Hibernate 用于创建 TRACK 表的真实 SQL 语句。如果你查看 data 目录下 music.script 文件的开头部分,就会发现它已经整合到数据库了。为了采用更友好的(也许是更方便的)方式来查看数据,可以执行 ant db 来启动 HSQLDB 图形界面,如图 2-1 所示。

图 2-1 显示新的 TRACK 表的内容以及一个查询的数据库管理器界面

细心的读者可能会问,既然 schema target 已经依赖于 prepare 了,那为什么要调用两次 Ant,第一次是运行 prepare,第二次是运行 schema。这是一种所谓的步步为营法(bootstrapping)的问题,只在第一次创建环境时才会遇到。具体问题是,Ant 在启动时会处理属性定义,以决定项目类路径的内容。直到 prepare 至少运行一次以前,classes 目录还不存在,也不会包含 hibernate.properties 文件,所以在类路径中也不包含这个目录。在 prepare 运行以后,才会在 classes 目录生成这个文件,而 classes 目录也才会包含在类路径中。但是 Ant 在下一次运行以前,不会重新设置属性定义。所以,如果你试图在第一次 Ant 运行时就运行 schema 目标,Hibernate 就会出现异常,向你报告没有指定一个数据库方言,因为它找不到配置属性文件。这种问题经常会导致令人困惑的尴尬。不过,从现在起,可以安全地直接运行 schema 目标了,并通过它来调用 prepare,按照需要复制新版本的属性文件,因为它们在 Ant 开始运行时,就已经在类路径中存在了。

发生了什么事

刚才我们已经能够使用 Hibernate 创建一个数据表了,以后我们可以将 Hibernate 为我们创建的 Java 类实例持久地保存在这个数据表中。我们没有输入任何一行 SQL 或 Java 语句!当然,我们的数据库表目前还是空的。来改变它吧!下一章会介绍你可能最想学习的主题:在 Java 程序中使用 Hibernate 将 Java 对象转换为数据库中的数据项,并进行相反的转换。

在深入探讨那种非常酷的任务之前,我们应该再回想一下通过一些 XML 和.properties 文件所能做到的诸多事项,这是非常有价值的。希望你已经开始看到 Hibernate 的强大功能和使用上的便利了。

其他

其他 ID 生成方法呢?主键(Key)在整个数据库中或全世界都是惟一的吗?Hibernate 支持很多为存储在数据库中的对象选择相应的主键的方法。这是由 generator 标签控制的,如例 2-1 的第 5 行所示。在这个示例中,我们告诉 Hibernate,对其遇到的数据库类型使用最自然的主键生成方法(native)。其他方法还包括流行的"hi/lo"算法、全局 UUID、完全由 Java 程序代码决定的方法以及其他多种方法。具体细节,可以参阅 Hibernate 参考手册文档中"Basic O/R Mapping"那一章的"generator"一节。此外,如果内建的各种方法都满足不了你的需要(时常如此),还可以提供你自己的类来做你想做的事情(实现 org.hibernate.id.Identifier-Generator 接口,再把实现类的名称放在 generator 标签内)。

如果你想学习一下用 Hibernate 连接你所更熟悉的数据库的示例,可以先看看第 10 章,这一章将演示如何用 Hibernate 处理 MySQL 数据库。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。