【Jsp精品源码栏目提醒】:本文主要为网学会员提供“JSP教程_Hibernate数据库持久层技术 - 其它资料”,希望对需要JSP教程_Hibernate数据库持久层技术 - 其它资料网友有所帮助,学习一下!
第 25 章 Hibernate数据库持久层技术 这一章将向读者介绍另一个非常流行的技术: Hibernate 数据库持久层。
为什么会产生这样的技术了,简单地说是由于传统的非面向对象的数据库设计总是和面向对象的程序设计格格不入,而 Hibernate 技术的产生正好改变了这一切,使程序开发人员可以从底层数据库设计中脱离处理。
Hibernate 是目前非常流行的 O/R Mapping(对象/关系映射)型框架,由于 EJB 非常笨重和繁琐(至少在 EJB3.0 还没有大行其道之前),所以 Hibernate 应该说是 O/R Mapping(对象/关系映射)型框架的最好选择。
那 Hibernate 持久层技术会带来怎样的好处以及如何使用,这一章节将向读者具体讲解。
Hibernate 学习中最为重要的是配置 XML 数据库映射文件和 HQL 语言的学习。
本章要点包括以下内容: Hibernate 数据库持久层技术概述 Hibernate 的安装和配置 Hibernate 中的 XML 映射文件详解 Hibernate 中的 HQL 语句介绍 25.1 Hibernate概述 首先通过本小节先认识一下什么是持久层以及 Hibernate 的相关概念和原理。
25.1.1 什么是持久层技术 数据持久层的设计目标是为整个项目提供一个高层、统一、安全和并发的数据持久机制。
完成对各种数据进行持久化的编程工作,并为系统业务逻辑层提供服务。
数据持久层提供了数据访问方法,能够使其它程序员避免手工编写程序访问数据持久层Persistene layer,使其专注于业务逻辑的开发,并且能够在不同项目中重用映射框架,大大简化了数据增、删、改、查等功能的开发过程,同时又不丧失多层结构的天然优势,继承延续 J2EE 特有的可伸缩性和可扩展性。
在 Web 应用系统开发过程中,使用 MVC(Model 模型-Veiw 视图-Controller 控制)模式作为系统的构架模式。
MVC 模式实现了架构上表现层(View)和数据处理层(即 Model)分离的解耦合。
但是由于 Model 模型层中包含了复杂的业务逻辑和数据逻辑,以及数据存储机制(例如 JDBC 连接、SQL语句生成、statement 创建以及 ResultSet 结果集的读取等操作)等。
为了将系统的紧耦合关系转化为松耦合关系(即解耦合),急迫需要将这些复杂的业务逻辑和数据逻辑进行分离,这就是持久层技术需要做的工作。
从开发者的角度来看,使用持久层技术的更为明显的原因是:在 Java 的数据库编程过程中,从前期的系统设计和分析, 到之后的 Java 编程等都是使用的面向对象的思想, 但是由于数据是关系型的非面向对象技术,所以到了数据层编程的时候,开发者会变得非常痛苦,他们需要编写面向过程的 SQL 语句。
一般在开发 J2EE 项目时,都要使用到
JSP、Servlet、JavaBean 以及 EJB 四个部分。
对于前三个读者应该比较熟悉了。
至于 EJB,它其实是 J2EE 中一个比较重要的部分,它给企业级开发提供了分布式406 Eclipse 从入门到精通技术的支持。
但是由于实际开发的大部分 Web 项目都是单服务器的轻量级项目(不需要分布式技术的支持),如果这时候使用 EJB 技术,就像大炮打蚊子,得不偿失。
而且 EJB 的复杂、繁琐和笨重是众所周知,其中的实体 bean 受到的批评最多。
本章将要介绍的是非常受开发者欢迎的 Hibernate 轻量级的持久层技术(至少在 EJB3.0 还没有一统天下的时候),它摈弃了 EJB 的繁琐和笨重,从使用和方便出发,致使它其中的许多设计均被 J2EE 标准组织吸纳而成为最新 EJB3.0 规范的标准。
25.1.2 Hibernate简介 Hibernate 是一个开放源代码的对象关系映射框架,它对 JDBC 进行了非常轻量级的对象封装,使得Java 程序员可以随心所欲的使用面向对象编程思维来操纵数据库。
Hibernate 可以应用在任何使用 JDBC的场合,既可以在 Servlet/
JSP 的 Web 应用中使用,也可以在 Java 的客户端程序实用,最具革命意义的是,Hibernate 可以在应用 EJB 的 J2EE 架构中取代 CMP,完成数据持久化的重任。
特别是对数据库管理系统来说,有了 Hibernate 之后,可以帮助开发者消除或者包装那些针对特定厂商的 SQL 代码,并且帮助开发者把结果从表格式的表现形式转换到一系列对象中去。
使得开发者没有必要再编写繁琐的面向过程的 SQL 语句,也不再需要把数据库表中的一个个字段拆开又组装。
这一切都交给 Hibernate 全部完成。
把开发者的工作从繁琐中解脱出来。
Hibernate 提供了一个和 SQL 语句非常类似的 HQL 语句,HQL 语句非常容易掌握并且有更多的优点(待会读者会体验到)。
另外,Hibernate 提供了智能化,可以动态根据实体对象和数据库表的状态自动进行更新、删除和插入。
如图 25.1 所示给出了 Hibernate 的高层概览。
Java应用 HQL语句 Hibernate.p XML映射文 roperties 件 SQL语句 数据库 图 25.1 Hibernate 结构概览 图 25.1 展示了 Hibernate 使用数据库和配置文件数据来为应用程序提供持久层服务(和持久化的对象)。
开发者编写的 HQL 语句最终也是会被 Hibernate 翻译成 SQL 语句,然后通过 JDBC 来访问数据库,但是这一切都是 Hibernate 自动完成的,开发者惟一需要配置的是 XML 数据映射文件(Hibernate就是通过这个映射文件把 HQL 语句翻译成 SQL 语句。
另外,针对不同的数据库,开发者必须指定使用 ,何种 SQL 方言) 这是开发者学习使用 Hibernate 最为关键的一部分,将花费开发者的大部分时间。
XML 第 18 章 常用插件扩展点 407映射文件定义了实体类(Entity Bean)和数据库表之间的关系,架起两者之间的桥梁。
Struts 框架和 Hibernate 持久层技术是开发 Web 应用的非常好的一个组合。
但是 Struts 框架只使用在Web 应用的开发中,而 Hibernate 还可以使用在 Application(包括 Eclipse 的插件开发)的开发项目中。
25.2 Hibernate的安装和配置 了解了 Hibernate 基本概念和原理之后,下面向读者介绍如何安装和配置 Hibernate。
25.2.1 下载Hibernate 下载 Hibernate 安装包可以登录 Hibernate 的官方网站 www.hibernate.org。
然后单击主页面左边的“Download”链接,本文使用的版本为 Hibernate3.1,下载的压缩包全名为 hibernate-3.1.zip。
如果在打开的页面中没有查看到此版本的 Hibernate,单击“Browse all Hibernate downloads”链接显示所有的Hibernate 版本产品。
然后把 Hibernate3.1 版本找到并下载下来,如图 25.2 所示。
将 hibernate-3.1.zip 解压之后得到多个文件夹和文件,如图 25.3 所示: Hibernate3.jar 包:这是 Hibernate 中的核心包。
Lib 目录:存放着一些第三方的支持包。
Src 目录:放置着 Hibernate2.jar 包的源文件。
Etc 目录:放置着可参考的多个例子。
Doc 目录:存放着各种文档文件,其中包括 pdf、多页面以及单页面多个格式,读者在之后的实 践过程中如果遇到什么问题,要善于查询这些文档。
图 25.2 下载 Hibernate 页面图 25.3 Hibernate 解压后的目录408 Eclipse 从入门到精通25.2.2 安装和配置Hibernate 安装和配置 Hibernate 的步骤如下: (1)将 hibernate-3.1.zip 解压之后得到的 hibernate3.jar 以及 lib 目录下的所有 jar 文件都复制到MyRegister 项目(这里以第 12 章创建的 MyRegister 项目为例)下的 Register/WEB-INF/lib 目录下。
特别说明: 其实在实际开发过程中,使用到的 Hibernate 的 jar 包很少。
这里复制所有 jar 文件,也只是为了 安装上的方便。
如果想了解实际开发过程中所使用到的 jar 文件,请参考压缩包中的 readme.txt 文件,或者参考 Hibernate 文档说明。
建议不要把这些 jar 包复制到 Tomcat/common/lib 目录下,那是 Tomcat 的全局库目录,如果同 时在一个服务器上安装多个 Web 应用时会容易出现包的冲突。
Hibernate 中的一个 commons-logging-1.0.4.jar 包其实和 struts 中的一个 commons-logging.jar 包一 样的,两者只要保留其中一个即可,否则会容易发生冲突。
(2)同安装 struts 一样把复制到 Register/WEB-INF/lib 目录下的所有 hibernate 的 jar 包添加到 Eclipse的库引用中,详细参考第 23 章。
如果开发者觉得库引用的包太多,影响操作,可以使用“过滤器”过滤掉一些不用的包。
首先把Eclipse 切换成“Java Browsing” 透视图格式, 然后如图 25.4 所示选择“Filters”命名。
弹出 “Java ElementFilters”对话框,在如图 25.5 所示的文本框中输入“.jar”,然后单击“ok”按钮,即可把不用的 jar文件过滤掉。
这一个步骤一般在项目开发完,准备打包之前去执行。
图 25.4 选择“Filters”命名 图 25.5 “Java Element Filters”对话框 (3)将解压包 etc 目录下的 log4j.properties 文件复制到 MyRegister 项目的将 j2src 目录下(原因与MessageResource.properties 资源文件一样)。
Log4j(本文对应的全名为 log4j-1.2.11.jar)是一个日志输出包,它是可选包。
如果引用了这个包,Commons Logging 就会使用 log4j 和它在上下文类路径中找到的 log4j.properties 文件输出数据操作的日志。
当没有创建 log4j.properties 文件时,程序运行时会发出警告信息,log4j 包无法起作用。
(4)第四步是一个比较关键的步骤,它要定义使用的数据库连接池参数以及定义 XML 数据库映射文件。
在 MyRegister 项目的 j2src 目录下创建一个 hibernate.cfg.xml 文件(也可以直接把 Hibernate 提供的例子中的 hibernate.cfg.xml 文件复制过来,再稍作修改),这是 Hibernate 的主配置文件。
这个配置文件的具体设置内容如下: ltDOCTYPE hibernate-configuration PUBLIC 第 18 章 常用插件扩展点 409 quot-//Hibernate/Hibernate Configuration DTD 3.0//ENquot quothttp://hibernate.sourceforge.net/hibernate-configuration-3.0.dtdquotgt lthibernate-configurationgt ltsession-factory namequotregisterquotgt lt-- database --gt ltproperty namequotconnection.datasourcequotgtjdbc/mysqllt/propertygt ltproperty namequotshow_sqlquotgttruelt/propertygt ltproperty namequotdialectquotgtorg.hibernate.dialect.MySQLDialectlt/propertygt lt-- define .hbm.xml here --gt ltmapping resourcequotcn/register/model.hbm.xmlquot/gt lt/session-factorygt lt/hibernate-configurationgt 代码说明: 在数据库定义中,属性 connection.datasource 设置了 Hibernate 所要使用到的连接池,这里的 jdbc/mysql 连接池就是之前在 Tomcat 服务器中设置的连接池,这表示 Hibernate 使用之前设置 好的连接池,并通过 DataSource 来获取。
show_sql 属性设置在控制台是否显示 Hibernate 生成的 SQL 语句,这里建议设置为“true”,便 于语句错误的检查。
dialect 属性值为 Hibernate 方言(Dialect)的类名,它可以使 Hibernate 使用某些特定的数据库 平台(例如 MySQL、Oracle、DB2 等数据库平台)。
这是因为各种数据库的 SQL 多多少少都 和 SQL 标准有差异,而 Hibernate 就是根据这里设置的方言来弥补这样的差异。
关于更多数据 库的方言请查看 Hibernate 自带实例的 hibernate.properties 文件。
model.hbm.xml 文件为 Hibernate 操作数据库表的映射关系表,通过该配置文件,Hibernate 把开 发者编写的 HQL 语句翻译成 SQL 语句然后对数据库表进行自动操作。
同样把这个映射关系表 创建在 MySQL 项目的 j2src 目录下, 然后在 hibernate.cfg.xml 配置文件种进行定义,使得 Hibernate 能够查找到这个映射文件。
关于这个映射关系文件的具体编写将在下一章的实例种具体讲解。
如果开发者还没有设置连接池,这时也可以使用 Hibernate 自带的连接池技术,具体设置也非常的简单,把以上 hibernate.cfg.xml 文件中的“ltproperty namequotconnection.datasourcequotgtjdbc/mysqllt/propertygt”代码替换成如下: ltproperty namequotconnection.driver_classquotgtcom.mysql.jdbc.Driverlt/propertygt ltproperty namequotconnection.urlquotgtjdbc:mysql://localhost/mydb1lt/propertygt ltproperty namequotconnection.usernamequotgtrootlt/propertygt ltproperty namequotconnection.passwordquotgt12345lt/propertygt ltproperty namequotc3p0.min_sizequotgt5lt/propertygt ltproperty namequotc3p0.max_sizequotgt20lt/propertygt ltproperty namequotc3p0.timeoutquotgt1800lt/propertygt ltproperty namequotc3p0.max_statementsquotgt50lt/propertygt 代码说明:C3P0(在 lib 目录下可以查看到 c3p0-0.9.0.jar 包)是随 Hibernate 发行包一起发布的一个开发源代码的 JDBC 连接池,这时需要设置 hibernate.c3p0.属性: connection.driver_class 属性:设置 MySQL 数据库驱动程序。
connection.url:配置数据库连接字串,mydb1 为需要连接的数据库。
connection.username:定义数据库登陆的用户名。
connection.password:定义以上用户名对应的密码。
410 Eclipse 从入门到精通 c3p0.min_size:设置在连接池中可用的数据库连接的最少数目。
c3p0.max_size:设置在连接池中所有数据库连接的最大数目。
c3p0.timeout:以秒为单位,如果空闲连接的空闲时间超过 timeout,就会被断开。
c3p0.max_statements:可以被缓存的 PreparedStatement 最大数目, 设置适量可大大提高 Hibernate 性能。
除了 hibernate.cfg.xml 配置文件的写法,还有一种 hibernate.properties 的写法,具体可以参考 etc 目录下的实例文件。
这里建议使用上一种 xml 配置方法。
25.3 Hibernate的实例讲解 上面只是讲解了一些 Hibernate 的概念和基本配置方法,读者可能对此还比较模糊。
下面将通过一个实例来简单演示 Hibernate 的使用过程。
25.3.1 Session对象 Session 是 Hibernate 执行的中心,是最为重要以及使用最为频繁的一个对象。
事物的生命周期、事务的管理、资料库的存取,都是与这个 Session 息息相关,就如同在编写 JDBC 时需要关心 Connection的管理,以有效的方法创建、利用与回收 Connection,以减少资源的消耗,增加系统执行效能一样。
有效的 Session 管理,也是 Hibernate 应用时需要关注的焦点。
这里的 Session 和
JSP 中的 session 不是一个概念,此处的 Session 是由 SessionFactory 所创建,SessionFactory 是执行时线程安全的 , (Thread-Safe)开发者可以让多个执行线程同时存取 SessionFactory而不会有资料共用的问题,然而 Session 则不是设计成线程安全的,所以试图让多个执行线程共用一个Session 时,将会发生资料共用而发生混乱的问题。
25.3.2 创建HibernateUtil类 接下来将创建最为关键的 HibernateUtil 类,该类封装了对 Session 进行统一管理(包括生成和关闭等操作)的各方法。
详细代码如下: package cn.register.db import org.apache.commons.logging.Log import org.apache.commons.logging.LogFactory import org.hibernate.HibernateException import org.hibernate.Session import org.hibernate.SessionFactory import org.hibernate.cfg.Configuration public class HibernateUtil private static Log log LogFactory.getLogHibernateUtil.class //定义一个日志 Log 对象 private static final SessionFactory sessionFactory //定义 SessionFactory 对象 static try 第 18 章 常用插件扩展点 411 //实例化一个 SessionFactory 对象 sessionFactory new Configuration.configure.buildSessionFactory catchThrowable ex //把异常错误写入到日志中 log.errorquotInitial SessionFactory creation failed.quotex throw new ExceptionInInitializerErrorex public static final ThreadLocal session new ThreadLocal public static Session currentSession throws HibernateException Session s Sessionsession.get //当 session 为空或者已经关闭的时候,就新创建一个 session 对象。
ifs nulls.isOpen s sessionFactory.openSession session.sets return s public static void closeSession throws HibernateException //关闭当前的 session Session s Sessionsession.get session.setnull ifsnull s.close 程序说明: 这里创建的 HibernateUtil 类是一个静态方法类, 以后需要调用 HibernateUtil.currentSession方法 创建一个 session 对象,通过 HibernateUtil. closeSession关闭 session。
程序当中通过一个 static…静态代码初始化一个 SessionFactory 实例。
读者需要特别注意的, 这里的 static…部分既不是定义的一个方法也不是一个变量, 只是调用这个类时会自动执行这 段代码。
前面已经提及,SessionFactory 类时线程安全的,但是 Session 不是线程安全的,所以这里使用 了 ThreadLocal 对象来把 Session 封装在当前工作线程中, 以免被多个线程同时访问而出现错误。
另外要注意的,Session 使用完毕之后一定要及时关闭,不然会损耗大量内存,在 Web 网站访 问的高峰时期,甚至会导致系统瘫痪。
这里的 currentSession方法会首先判断当前 session 是否为空, 如果为空, 则重新打开一个 session 并返回。
closeSession方法用于及时关闭当前的 session 对象,释放内存。
这个 HibernateUtil 类一旦创建好,就很少进行修改。
412 Eclipse 从入门到精通25.3.3 创建model.hbm.xml数据库映射文件 如果没有下面创建的数据库映射文件 model.hbm.xml,Hibernate 是不会知道相应实体类如何操作对应的数据库表。
此处的示范实例只涉及到一张用户信息表 users (本实例直接使用在第 12 章中创建的 users 。
表) Hibernate 不能使用接口或者抽象类作为实体类, 所以下面重新创建用户信息的实体类 DBUser.java(类似于 AbstractUser.java 抽象类),详细源代码如下: package cn.register.user public class DBUser implements User private String user_id //用户名 private String password //用户密码 private String name //用户姓名 private String sex //用户性别 private long birth //用户出生年月 private String description //用户描述 public void setUser_idString user_id this.user_id user_id public String getUser_id return user_id public void setPasswordString password this.password password public String getPassword return password public void setNameString name this.name name public.