第二章:使用原生Hibernate API 和hbm.xml映射
(示例代码下载地址http://sourceforge.net/projects/hibernate/files/hibernate4/)
2.1. Hibernate configuration 文件资源文件hibernate.cfg.xml定义了Hibernate的配置信息。
比如说connection.driver_class,connection.url,connection.username 和connection.password等属性元素定义了JDBC连接的信息。由于本套教程利用了H2的“内存间”(in-memory)模式,所以以上这些属性的值都是运行在H2的in-memory模式上的特定的值。connection.pool_size是用来配置在Hibernate内置连接池的连接数。
(重要:Hibernate内置连接池不是专门为生产环境使用的,他缺少了许多生产环境下连接池该有的特性)。
“dialect”属性指定了Hibernate将会转换的目标特定SQL变体(如MySQL的具体语句,Oracle的具体语句等)。
(提示:在大多数情况下,Hibernate能够正确地判断使用哪种dialect,这对于面对多种数据库的应用就非常有用)。
“hbm2ddl.auto”属性让Hibernate能够直接给数据库生成简单元数据纲要(如数据库,数据库表结构等)。
最后,为持久化类添加映射文件到配置中,mapping元素的“resource”属性促使Hibernate尝试定位该映射作为类路径的资源,并且使用java.lang.ClassLoader来搜寻。
2.2. 实体类
本教程的实体类为org.hibernate.tutorial.hbm.Event。
关于实体类的说明:
》Event类使用标准的JavaBean命名规范,为属性生成getter和setter方法,并且所有字段都为private的,尽管这是推荐的设计方法,但却不是必须不可的。
》同样作为JavaBean命名规范的无参构造函数,也是所有持久化类应有的。因为Hibernate需要使用反射机制来为我们创建这些类的对象。构造方法可以使private的,但是包内可见或者全局可见(package或者public可见)是运行时生成代理和非字节码调试高效数据检索的必须。
2.3. 映射文件
本教程的映射文件hbm.xml路径为/org/hibernate/tutorial/hbm/Event.hbm.xml。
Hibernate使用映射的元数据来决定如何加载和存储持久化对象,Hibernate映射文件是为Hibernate提供这些元数据的一种选择。
例:2.1 class 映射元素
<class name="Event" table="EVENTS">
…
</class>
class 元素的功能:
1.name属性指定了将会作为持久化的实体类名(要结合package属性)。
2.table属性指定了包含该实体数据的数据库表。
有了class属性之后,现在Event类的所有实例化对象就与数据库中EVENTS表中
的行一一对应了。
例:2.2 id 映射元素
<id name="id" column="EVENT_ID">
…
</id>
Hibernate使用id元素的指定的属性值来唯一的标志表中的每一行。
(重要:id元素不是必须得映射到表中的primary key(主键),但是这事传统的做法。在Hibernate中被映射的表甚至不需要主键。尽管如此,还是强烈建议所有的元数据都定义引用完整性。因此id和主键在Hibernate的文档中都可交换使用)。
ID元素标志了EVENT_ID列作为EVENTS表的主键,同时也标志了类Event的ID字段包含了唯一标志的值。
generator元素嵌套在id元素内部告知Hibernate使用哪种策略来为实体类生成主键。
例:2.3. property 映射属性
<property name="data" type="timestamp" column="EVENT_DATE"/>
<property name="Title"/>
以上两个属性元素声明了Event剩下的两个字段:date和title。date属性包含了column属性,但是title属性没有。如果没有指定column属性,Hibernate使用相同的属性名来作为column(列)名。title刚好可以做到让类字段名和数据库表列名一致,但是由于date是大多数数据库保留的关键字,因此需要为date指定另外的列名。
title元素缺少了type属性,在映射文件中的type属性既不是Java的类型也不是SQL数据库中的类型,而是Hibernate映射类型。Hibernate映射类型是在Java和SQL之间充当翻译官的转换器。如果type 属性没有在映射中被指定,Hibernate会自动尝试使用正确的转换,原理是通过Java反射机制来判断。
某些情况下这种自动的探测可能不会选择到你期望或者需要的默认类型,就像date属性一样,Hibernate无法知道java.util.Date类型应该映射到SQL中的DATE,TIME还是TIMESTAMP类型。在映射文件中完整的日期和时间信息应该映射到timestamp转换器,在Hibernate中是org.hibernate.type.TimestampType类型。
2.4. 示例代码
类org.hibernate.tutorial.hbm.NativeApiIllustrationTest展示了如何使用Hibernate本地的API。
(提示:被教程的所有示例代码都是在JUnit下测试,为了容易,一个方法就是在@before和@after下分别建立和销毁SessionFactory)。
例:2.4. 获得org.hibernate.SessionFactory
protected void setUp() throws Exception {
// 一个程序中SessionFactory只要建立一次
sessionFactory = new Configuration()
.configure() // configures settings from hibernate.cfg.xml
.buildSessionFactory();
}
工作流程:
1.加载配置文件
最先察觉配置文件的就是org.hibernate.cfg.Configuration类。本教程所有配置细节都在http://hibernate.org/documentation/quickstart/en-US/html/ch02.html#hibernate-gsg-tutorial-basic-config
2.创建org.hibernate.SessionFactory
然后org.hibernate.cfg.Configuration创建org.hibernate.SessionFactory对象,org.hibernate.SessionFactory对象是一个线程安全的对象,在整个应用中只需要实例化一次(单例模式)。
3.SessionFactory创建Session实例。
SessionFactory作为Session实例的一个工厂,可以在示例代码中testBasicUsage方法中看到。
4.Session对象开始工作
一个session对象应该要执行一个单一的工作单元。
例:2.5. 保存实体(持久化实体)
Session session = sessionFactory.openSession();
session.beginTransaction();
session.save( new Event( "Our very first event!", new Date() ) );
session.save( new Event( "A follow up event", new Date() ) );
session.getTransaction().commit();
session.close();
testBasicUsage方法首先创建一些Event对象,使用save方法将之传递给Hibernate管理,Hibernate负责使用INSERT语句将他们插入到数据库。
例:2.6. 获得一系列实体对象
session = sessionFactory.openSession();
session.beginTransaction();
List result = session.createQuery( "from Event" ).list();
for ( Event event : (List<Event>) result ) {
System.out.println( "Event (" + event.getDate() + ") : " + event.getTitle() );
}
session.getTransaction().commit();
session.close();
testBasicUsage展示了如何使用Hibernate Query Language(HQL:Hibernate查询语言)来加载数据库中所有Event对象的,生成适当的SELECT SQL语句,发送到数据库并且使用返回的结果集填充Event对象。
2.5. 更深入地。。。
实际操作练习:
》重新配置示例代码连接到你自己的数据库