- 译者序
- 前言
- 本书怎么使用
- 本书排版字体约定
- 本书网站
- 致谢
- 第一部分 Hibernate 快速入门
- 第 1 章 安装和设置
- 第 2 章 映射简介
- 第 3 章 驾驭 Hibernate
- 第 4 章 集合与关联
- 第 5 章 更复杂的关联
- 第 6 章 自定义值类型
- 第 7 章 映射标注
- 第 8 章 条件查询
- 第 9 章 浅谈 HQL
- 第二部分 与其他工具的集成
- 第 10 章 将 Hibernate 连接到 MySQL
- 第 11 章 Hibernate 与 Eclipse:Hibernate Tools 使用实战
- 第 12 章 Maven 进阶
- 第 13 章 Spring 入门:Hibernate 与 Spring
- 第 14 章 画龙点睛:用 Stripes 集成 Spring 和 Hibernate
- 附录 A Hibernate 类型
- 附录 B Criteria API
- 附录 C Hibernate SQL 方言
- 附录 D Spring 事务支持
- 附录 E 参考资源
- 作者简介
- 封面介绍
编制数据库 Schema
刚才真简单,对吧?根据映射来创建数据库表也差不多是这样,你会很愉快地学习下去。和代码生成一样,只要利用映射文件,几乎所有工作都做完了。剩下的就是设置和运行 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 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论