|
JDO、JDBC 和 Hibernate
JDO 简介
Java Data Object(JDO) API 是标准、基于接口的持久性 Java 模型抽象,可以直接把 Java 域模型实例保存到数据存储。JDO 是作为 Java Specification Request 的一部分开发的。
开发应用程序时,程序员可以用 Java 编程语言编写代码,透明地访问底层数据存储,而不需要编写特定于数据库的代码。JDO 技术的特性有:
- 可移植性:用 JDO API 编写的应用程序可以运行在多个实现上,不需重新编译或修改源代码。
- 数据库独立性:用 JDO API 编写的应用程序独立于底层数据库。
- 专注于域模型:程序员现在可以专注于他们的域模型,把持久性的细节问题留给 JDO 实现处理。
- 高性能:程序员可以把持久性的细节委托给 JDO 实现,JDO 实现能够优化数据访问模式,从而获得最佳性能。
JDBC 简介
Java Database Connectivity(JDBC)API 是作为 Java 2 标准版(J2SE)和 Java 2 企业版(J2EE)平台的关键部分出现的。它是 Java 语言以编程方式访问关系数据库的基于标准的首要机制。
JDBC API 为程序员提供了极大的灵活性,它提供了对数据库访问和缓存管理的直接控制。JDBC API 是项成熟的技术,是一种完善且已得到充分认识的 API,因而得到业内的广泛认同。
当前的 JDBC 版本(3.O)对旧版本进行了许多必要的改进。DB2 8 及之后的版本完全支持 JDBC 3.0 API。许多特性,例如从数据库检索自动生成键的能力、打开多个结果集的能力、改进的连接和语句池等都是 JDBC 3.0 中值得称道的新能力。例如,清单 1 显示了用 JDBC 3.0 检索自动生成键的代码片段:
清单 1. JDBC 自动生成键
Statement stmt = conn.createStatement(); //Obtain the generated` key from query. stmt.executeUpdate("INSERT INTO Accounts " + "(account_name, balance) " + "VALUES ('Smith Savings Account', 500.00)", Statement.RETURN_GENERATED_KEYS);
ResultSet rs = stmt.getGeneratedKeys(); if ( rs.next() ) { // Retrieve the auto generated key(s) i.e account_id. int accountIdkey = rs.getInt(1); } | Hibernate 简介
Hibernate 是个强大的、高性能的对象/关系持久性和查询服务。Hibernate 支持开发符合面向对象风格的持久性类,包括关联、继承、多态、复合和集合。Hibernate 允许您用它自己的可移植 SQL 扩展(HQL)表示查询,也可以用纯粹的 SQL 或面向对象方式和示例 API 表示。与其他许多持久性解决方案不同,Hibernate 没有使您失去使用 SQL 的力量,从而保证了在关系技术上的现有投资和知识一直有效。
Hibernate 是专业的开放源码项目,比起其他持久性框架,它是应用和接受最为广泛的框架。像 Spring 这样的框架提供了对 Hibernate 丰富的支持,在这里 Spring 的面向方面编程(AOP)框架为开发人员提供了一种声明式地提供 Hibernate 事务的方式。
Hibernate 用 XML(*.hbm.xml)文件把 Java 类映射到表,把 Java Beans? 属性映射到数据库表。通过 JDBC 支持全部 SQL 数据库管理系统。Hibernate 可与所有流行的 J2EE 应用服务器和 Web 容器完美集成。
Hiābernate 与 JDO 的比较
Hibernate 是一种得到广泛信任和采用的持久性框架,比 JDO 这样的规范更成熟。两个框架在提供持久性时,都可以直接把 Java 域对象保存到持久存储。由于 JDO 是 Java 规范的一部分,而 Hibernate 具有开放源码这样的背景,所以在未来的一段时间内,JDO 仍将在一段时间内得到不同厂商的认同。
如果在 Hibernate 未来的发行版中,能在现有的开放源码持久性框架上提供对 JDO 的支持,将会很好,这样就可以把 JDO 规范的强大力量与 Hibernate 可靠的开放源码特性结合。
开始
在这份教程中,我们将构建一个示例应用程序,它整合了 Spring AOP 的声明式事务处理,以及 Spring 加 Hibernate 的持久性主干。Spring 是个开放源码框架,它的创建是为了解决企业应用程序开发的复杂性问题。Spring 是面向控制和面向方面的容器框架的轻量级版本。 Spring 框架提供了 AOP 框架、JDBC DAO 抽象、与 ORM 框架(像 JDO、Hibernate 和 IBATIS SQL 映射)的集成,带有声明式事务支持以及构建 Web 应用程序的全功能 MVC 框架。
Spring 的功能可以用于任何 J2EE 服务器,多数功能也可以用于非托管环境。Spring 的一个核心重点就是允许使用未绑定到特定 J2EE 服务上的可重用业务和数据访问对象。这类对象可以跨 J2EE 环境(Web 或 EJB)、独立应用程序、测试环境等重用,毫无困难。
我们的示例应用程序代表一个示例企业,其中包含多个部门和员工。我们的示例应用程序需要创建一个名为 orgdb 的 DB2 数据库,这也是即将介绍的第一步。 SampleOrgDB 容纳部门和员工信息。假设部门和员工之间的关联是 1:N。
创建示例数据库
本节创建示例企业应用程序要使用的示例数据库。创建容纳部门和员工信息的示例 orgdb 数据库。创建源表的方法如下:
在 Windows 命令行提示符下,输入 db2cmd。
输入以下语句,创建所需数据库:
db2 create database orgdb
按下 Enter 键。
现在我们已经创建好了企业数据库。容纳部门和员工应用程序的表将由示例 Hibernate 应用程序创建。
构建示例应用程序
这一节用 Spring AOP 和 Hibernate 构建并逐步检查示例企业应用程序,程序将在 DB2 数据库中保存一个 Java 对象。应用程序允许企业添加部门和属于这些部门的员工。
为数据库交互实现 DOA(数据访问对象)模式。把 Spring AOP 的 TransactionProxyFactoryBean 设置为拦截方法调用,并声明式地把事务上下文应用到任何事务密集型操作的 DOA 上。
为 DB2 设置 JDBC 数据源和 HibernateSessionFactory
在 Spring 框架中,JDBC DataSource 或 Hibernate SessionFactory 这样的资源在应用程序上下文中可视为 bean。需要访问资源的应用程序对象只要通过 bean 引用检索到这类预定义实例的引用即可(下一节将更详细地介绍这方面的内容)。在 清单 2 中,可以看到从示例应用程序摘录的一段代码:XML 应用程序上下文定义,显示了如何设置 JDBC DataSource 及其上的 Hibernate SessionFactory。
清单 2 显示了如何为示例应用程序数据库(DB2)配置数据源 bean(exampleDataSource)。driverClassName 代表类型 Type 4 DB2 Java 类(com.ibm.db2.jcc.DB2Driver),url 代表 orgdb 数据库的位置(jdbc:db2://localhost:50000/orgdb)。将数据库连接 URL 中包含的主机名(localhost)和端口号(50000)改成 db2 服务器实际安装的位置。Hibernate.dialect 属性的值是 “net.sf.hibernate.dialect.DB2Dialect”,它指定 hiābernate 使用 DB2 术语,表示您处理的是 DB2 数据库。对于其他数据库服务器,这个值会有不同。例如,若要在 Derby 上运行应用程序,值应是 “net.sf.hibernate.dialect.DerbyDialect”。
exampleDataSource bean 被织入 Spring Hibernate 的 SessionFactory。请注意 *.hbm.xml 表示示例应用程序的 OR 映射文件。
清单 2. JDBC 数据源和 HibernateSessionFactory 织入
<bean id="exampleDataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName"><value>com.ibm.db2.jcc.DB2Driver</value></property>
<property name="url"><value>jdbc:db2://localhost:50000/orgdb</value></property>
<property name="username"><value>db2admin</value></property>
<property name="password"><value>db2admin</value></property>
</bean>
<bean id="exampleHibernateProperties"
class="org.springframework.beans.factory.config.PropertiesFactoryBean">
<property name="properties">
<props>
<prop key="hibernate.hbm2ddl.auto">update</prop>
<prop key="hibernate.dialect">net.sf.hibernate.dialect.DB2Dialect</prop>
<prop key="hibernate.query.substitutions">true 'T', false 'F'</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.c3p0.minPoolSize">5</prop>
<prop key="hibernate.c3p0.maxPoolSize">20</prop>
<prop key="hibernate.c3p0.timeout">600</prop>
<prop key="hibernate.c3p0.max_statement">50</prop>
<prop key="hibernate.c3p0.testConnectionOnCheckout">false</prop>
</props>
</property>
</bean>
<!-- Hibernate SessionFactory -->
<bean id="exampleSessionFactory"
class="org.springframework.orm.hibernate.LocalSessionFactoryBean">
<property name="dataSource"><ref local="exampleDataSource"/></property>
<property name="hibernateProperties">
<ref bean="exampleHibernateProperties" />
</property>
<!-- Must references all OR mapping files. -->
<property name="mappingResources">
<list>
<value>Department.hbm.xml</value>
<value>Employee.hbm.xml</value>
</list>
</property>
</bean>
|
织入 DAO 层
数据源和会话工厂设置好后,下一步是在织入 DAO(本例中为 DepartmentDAO)以便使用 SessionFactory。接下来,插入 Spring 的 TransactionProxyFactoryBean,它将拦截对应用程序的 DepartmāentDAOImpl 对象的方法调用,并声明式地在上面应用事务上下文。
在这个示例中,DepartmentDAOImpl 类的 addDepartment 方法作为事务的一部分执行,带有事务属性 PROPAGATION_REQUIRED。这个属性相当于 EJB 容器的 TX_REQUIRED。如果希望让方法总是在事务中运行,可以使用 PROPAGATION_REQUIRED。如果事务已运行,bean 方法会加入这个事务,或者 Spring 轻量级事务管理器会另行启动一个事务。如果想在调用组件服务时总是启动新事务,可以使用 PROPAGATION_REQUIRES_NEW 属性。
清单 3. 编织应用程序的 DAO 和 TransactionManager
<!-- Pass the session factory to our DepartmentDAO -->
<bean id="departmentDAOHelper" class="springexample.db2persist.hibernate.DepartmentDAOHelper"> <property name="departmentDAO"><ref local="departmentDAOTarget"/></property> </bean>
<bean id="departmentDAO" class="springexample.db2persist.hibernate.DepartmentDAOImpl"> <property name="sessionFactory"><ref local="exampleSessionFactory"/></property> </bean>
<bean id="transactionManager" class="org.springframework.orm.hibernate.HibernateTransactionManager"> <property name="sessionFactory"><ref bean="exampleSessionFactory"/></property> </bean>
<bean id="departmentDAOTarget" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"> <property name="transactionManager"><ref local="transactionManager"/></property> <property name="target"><ref local="departmentDAO"/></property> <property name="transactionAttributes"> <props> <prop key="addDepartment">PROPAGATION_REQUIRED</prop> </props> </property> </bean> | 有了这个之后,应用程序的织入就完成了。我们来看源代码。
分析源代码
如果您还没有下载文章的源代码 (DB2SpringHB.zip),请从 下载 部分中下载。把源 zip 文件释放到桌面的任意位置,例如 c:\。会创建叫做 DB2SpringHB 的文件夹。src\spring 文件夹包含示例应用程序的 Hibernate 映射文件和 Spring 配置文件。src\springexample\db2persist\hibernate 文件包含应用程序的源代码。
在这里会找到两个类,名称分别为 Department 和 Employee,它们用 Hibernate 的映射文件 Department.hbm.xml 和 Employee.hbm.xml 映射到两个表。Department 类代表部门信息,Employee 类代表与部门相关的员工信息。前面已经提到过,我们用 1: N 关系为这两个类建模,其中一个 Department 包含多个 Employee。 清单 4 显示了 Department 对象的 Hibernate 映射文件。
清单 4. Department 对象的 Hibernate 映射文件
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 2.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd">
<hibernate-mapping>
<class
name="springexample.db2persist.hibernate.Department"
table="TBL_DEPARTMENT"
dynamic-update="false"
dynamic-insert="false">
<id
name="id"
column="DEPARTMENT_ID"
type="java.lang.Long"
unsaved-value="-1"
>
<generator class="native">
</generator>
</id>
<set name ="employees"
inverse = "true"
outer-join="auto"
cascade="all-delete-orphan">
<key column ="EMPLOYEE_ID"/>
<one-to-many class="springexample.db2persist.hibernate.Employee"/>
</set>
<property
name="name"
type="string"
update="false"
insert="true"
column="DEPARTMENT_NAME"
length="60"
not-null="true"
/>
</class>
</hibernate-mapping>
| set name="employees" 和一对多类标记表示 Department 和 Employee 之间的关系。generator class="native" 表示 Hibernate 将使用 DB2 自己的标识值生成方法生成主键。
分析 DAO 源代码
DepartmentDAOImpl.java 代表应用程序的 DAO,它把部门和员工信息插入应用程序数据库。DepartmentDAOImpl 扩展了 Spring 的 HibernateDaoSupport,它用 Spring 的 HibernateTemplate 简化了会话管理。这样就可以通过 getHibernateTemplate() 方法保存或检索数据。清单 5 所示的 getDepartmentEmployees() 用 HQL 和 getHibernateTemplate().find 方法对 Department 进行 find 操作,找到所有属于这个部门的员工。
清单 5. DAO 实现
public class DepartmentDAOImpl extends HibernateDaoSupport implements DepartmentDAO{ public void addDepartment(Department department) { getHibernateTemplate().save(department); }
public Department getDepartmentEmployees(Department department) {<āp> Department dep = null; List list = getHibernateTemplate().find("from Department department " + "where department.id = ?" , department.getId(),Hibernate.LONG);
if(list.size() > 0){ dep = (Department) list.get(0); } return dep; } } | 现在来看看代码运行的效果吧!
运行应用程序
要运行示例应用程序,首先必须下载 Spring 框架及其全部相关文件。然后,解压框架(比如说解压到 c:\ 目录下),创建 C:\spring-framework-1.2-rc2 (针对当前发行版)的文件夹。在继续之前,还必须下载并解压 Apache Ant。
接下来,把源代码释放到一个文件夹,例如 c:\,创建 DB2SpringHB 文件夹。再修改 build.xml 文件入口,用实际安装 Spring 的位置替换 C:\spring-framework-1.2-rc2,用 DB2 Type 4 JDBC 驱动程序所在的位置替换 C:\Installables\IBM\SQLLIB\java\。
打开命令提示符,更改目录到 DB2SpringHB,在命令提示符中输入以下命令:build。
这会构建并运行 CreateDepartmentEmployeeClient 类,该类又创建 Department 类对象,为其填充一些数据,创建 Employee 对象,为它填充数据,并把它添加到 Department 对象。
然后 CreateDepartmentEmployeeClient 调用 DepartmentDAOHelper.addDepartment 类,添加部门和员工信息。一旦插入,CreateDepartmentEmployeeClient 就会调用 DepartmentDAOHelper.getDepartmentEmployees 方法,根据部门 id 得到部门和员工信息。如果 CreateDepartmentEmployeeClient 成功执行,将看到部门名称和员工信息输出到控制台。也可以查询 DB2 数据库,检索部门和员工信息。
验证 DB2 数据库中的记录
为了验证 orgdb 数据库中的记录,请执行以下步骤:
在 Windows 命令提示符下,输入 db2cmd
输入以下语句:
db2 connect to orgdb
db2 select * from tbl_department
db2 select * from tbl_employee
您将看到保存在 DB2 数据库中的记录。
至此,您已成功地测试了示例企业应用程序。
结束语
在这份教程中,您学习了在 DB2 数据库中保持数据的各种方法,并逐步查看了构建示例应用程序的过程,示例应用程序整合了 Spring AOP 的声明式事务处理,并用 Spring 加 Hibernate 的持久性主干在 DB2 数据库中保持 Java 对象。这个基本的应用程序成为一个起点,使您快速走上为 DB2 数据库构建高度可维护、基于持久性的应用程序的大道。
|