1.2.2. 映射文件
Hibernate需要知道怎样去加载(load)和存储(store)持久化类的对象。这正是Hibernate映射文件发挥作用的地方。映射文件告诉Hibernate它,应该访问数据库(database)里面的哪个表(table)及应该使用表里面的哪些字段(column)。
一个映射文件的基本结构看起来像这样:
<?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>
[...]
</hibernate-mapping>
注意Hibernate的DTD是非常复杂的。你的编辑器或者IDE里使用它来自动完成那些用来映射的XML元素(element)和属性(attribute)。你也可以在文本编辑器里打开DTD-这是最简单的方式来概览所有的元素和attribute,并查看它们的缺省值以及注释。注意Hibernate不会从web加载DTD文件,但它会首先在应用程序的classpath中查找。DTD文件已包括在hibernate3.jar
里,同时也在Hibernate发布包的src/
目录下。
为缩短代码长度,在以后的例子里我们会省略DTD的声明。当然,在实际的应用程序中,DTD声明是必须的。
在hibernate-mapping
标签(tag)之间, 含有一个class
元素。所有的持久化实体类(再次声明,或许接下来会有依赖类,就是那些次要的实体)都需要一个这样的映射,来把类对象映射到SQL数据库里的表。
<hibernate-mapping>
<class name="events.Event" table="EVENTS">
</class>
</hibernate-mapping>
到目前为止,我们告诉了Hibernate怎样把Events
类的对象持久化到数据库的EVENTS
表里,以及怎样从EVENTS
表加载到Events
类的对象。每个实例对应着数据库表中的一行。现在我们将继续讨论有关唯一标识符属性到数据库表的映射。另外,由于我们不关心怎样处理这个标识符,我们就配置由Hibernate的标识符生成策略来产生代理主键字段。
<hibernate-mapping>
<class name="events.Event" table="EVENTS">
<id name="id" column="EVENT_ID">
<generator class="native"/>
</id>
</class>
</hibernate-mapping>
id
元素是标识符属性的声明,name="id"
声明了Java属性的名字 - Hibernate会使用getId()
和setId()
来访问它。 column
属性则告诉Hibernate, 我们使用EVENTS
表的哪个字段作为主键。嵌套的generator
元素指定了标识符生成策略,在这里我们指定native
,它根据已配置的数据库(方言)自动选择最佳的标识符生成策略。Hibernate支持由数据库生成,全局唯一性(globally unique)和应用程序指定(或者你自己为任何已有策略所写的扩展)这些策略来生成标识符。
最后我们在映射文件里面包含需要持久化属性的声明。默认情况下,类里面的属性都被视为非持久化的:
<hibernate-mapping>
<class name="events.Event" table="EVENTS">
<id name="id" column="EVENT_ID">
<generator class="native"/>
</id>
<property name="date" type="timestamp" column="EVENT_DATE"/>
<property name="title"/>
</class>
</hibernate-mapping>
和id
元素一样,property
元素的name
属性告诉Hibernate使用哪个getter和setter方法。在此例中,Hibernate会寻找getDate()/setDate()
, 以及getTitle()/setTitle()
。
为什么date
属性的映射含有column
attribute,而title
却没有?当没有设定column
attribute 的时候,Hibernate缺省地使用JavaBean的属性名作为字段名。对于title
,这样工作得很好。然而,date
在多数的数据库里,是一个保留关键字,所以我们最好把它映射成一个不同的名字。
另一有趣的事情是title
属性缺少一个type
attribute。我们在映射文件里声明并使用的类型,却不是我们期望的那样,是Java数据类型,同时也不是SQL数据库的数据类型。这些类型就是所谓的Hibernate 映射类型(mapping types),它们能把Java数据类型转换到SQL数据类型,反之亦然。再次重申,如果在映射文件中没有设置type
属性的话,Hibernate会自己试着去确定正确的转换类型和它的映射类型。在某些情况下这个自动检测机制(在Java 类上使用反射机制)不会产生你所期待或需要的缺省值。date
属性就是个很好的例子,Hibernate无法知道这个属性(java.util.Date
类型的)应该被映射成:SQL date
,或timestamp
,还是time
字段。在此例中,把这个属性映射成timestamp
转换器,这样我们预留了日期和时间的全部信息。
应该把这个映射文件保存为Event.hbm.xml
,且就在Event
Java类的源文件目录下。映射文件可随意地命名,但hbm.xml
的后缀已成为Hibernate开发者社区的约定。现在目录结构看起来应该像这样:
.
+lib
<Hibernate and third-party libraries>
+src
+events
Event.java
Event.hbm.xml
我们继续进行Hibernate的主要配置。