1) 介紹
最近我參與了北美一家銀行的審計系統的後台軟體設計和開發工作,除了使用Web Service以外,我們集成了Spring和Hibernate,通過Spring的HibernateTemplate實現了對資料庫數據的存取.眾所周知Hibernate是一種廣泛應用的一種強大的數據持久層技術, 另一方面Spring作為支持IOC的依賴注入框架, 其優點是能夠非常好地集成大多數主流技術. 本文我們將討論如何集成 Spring 和Hibernate.
2) Spring和Hibernate基礎
在我們實際進入集成這兩個技術之前,讓我們理解這種集成需求,大家都知道Hibernate是一種位於應用和資料庫之間的強大的ORM 工具. 它可使應用以獨立平台的方式從各種資料庫訪問數據,對應用來說沒有必要依賴於低級DBC 細節如管理連接, 處理statements 和result sets. 所有訪問特定數據源的細節很容易在Xml文件中配置,另一個好處是Hibernate和J2SE和J2EE應用兼容得很好.
使用Hibernate 問題之一是使用Hibernate Framework訪問資料庫的客戶應用必須依賴Hibernate APIs如Configuration, SessionFactory and Session. 這些個對象在應用代碼中持續擴散.應用代碼必須用手工維護和管理這些對象.但是在Spring的環境, 業務對象通過IOC的幫助下是能夠通過配置完成的,簡單地說,一個對象狀態能夠從應用代碼中分離.意思是現在使用Hibernate 對象作為Spring Beans是可能的,他們能夠得到Spring提供的所有方便.
3) 集成Sample
我們沒有打算研究Spring包里集成的各種API,我們想通過實例源碼來學習和理解這些APIs. 下列部分包括了集成Spring-Hiberante 的每個步驟並附有詳細的解釋.
3.1) 創立資料庫
下面的應用使用Oracle資料庫. Oracle10g的express版本可以從http://www.oracle.com/technology/products/database/xe/index.html免費下載,安裝后, 先用管理員身份登錄和創建用戶schema,username and password,再以用戶身份登錄後去SQL command 或SQL Script運行以下SQL statement :create table Activitylog(id varchar(10), name varchar(20), taskcode varchar(3), tasktime timestamp);現在一個空表已創立.
3.2) ActivityLog類
現在讓我們創建叫做Activitylog POJO代碼用於存儲從Activitylog表取出的數據,此類的設計使表'Activitylog'的列名將被映射到Java類Activitylog適當類型的變數名. 可使用ant工具或plug-in產生,Activitylog類完整的代碼列舉如下:
package com.xxx.audit.pojo; public class Activitylog { private String id; private String name; private String taskcode; private Timestamp tasktime; public Activitylog () { } public String getId(){ return id; } public void setId(String id){ this.id = id; } public String getName(){ return name; } public void setName(String name){ this.name = name; } public String getTaskcode(){ return taskcode; } public void setTaskcode(String taskcode){ this.taskcode = taskcode; } public Timestamp getTasktime(){ return tasktime; } public void setTasktime(Timestamp tasktime){ this.tasktime = tasktime; } public String toString(){ return "Id = " id ", Name = " name ", Taskcode = " taskcode ", Tasktime = " tasktime; } } |
注意toString() 方法重寫是為了Activitylog 對象的顯示.
3.3) 創建Hibernate Mapping 文件
我們已經在資料庫中創建了'Activitylog' 表和一個在應用層相應的Java類 class,我們需要創建Hibernate Mapping文件去把'Activitylog' 表映射到'Activitylog' Java 類,'Activitylog' 表的列名映射到'Activitylog' Java 類的變數,可使用ant工具或plug-in產生,讓我們看看Hibernate Mapping文件:
Activitylog.hbm.xml <?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> <class name="com.xxxx.audit.pojo.activitylog" table=" activitylog "> <id name="id" column="Id"> <generator class="assigned"/> </id> <property name="name"> <column name="Name"/> </property> <property name="taskcode"> <column name="Taskcode"/> </property> <property name="tasktime"> <column name="Tasktime"/> </property> </class> </hibernate-mapping> |
注意映射文件是一個Xml文件並且它的名字是Activitylog.hbm.xml. 文件名中'hbm' 代表它是Hibernate映射文件. class 標記定義了資料庫表和Java類之間的映射. 'name' 屬性必須指向一個全路徑的Java類名,反之表屬性必須指向資料庫表,接下來的標記定義了列名和對應java變數之間的映射,'id' 標記作為主鍵定義了一行的標識,property標記有一個屬性叫'name' 指向Java變數名, 接下來的是它映射的資料庫表的列名.
3.4) 創立Spring配置文件
這部分處理配置各種Spring需要的信息. 在Spring全部的業務對象在Xml文件中配置,配置的業務對象叫做 Spring Beans.這些Spring Beans可通過IOC維護,讓我們定義一個data source如下,
spring-hibernate.xml <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd"> <bean id="myDataSource" class="org.apache.commons.dbcp.BasicDataSource" > <property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"/> <property name="url" value="jdbc:oracle:thin:@localhost:1521:XE"/> <property name="username" value="root"/> <property name="password" value="root"/> </bean> ? </beans> |
上面bean定義了一個類型'org.apache.commons.dbcp.BasicDataSource'的data-source. 更重要的是, 它定義了各種訪問資料庫所需要的連接屬性.
現在讓我們定義第二個Spring Bean:SessionFactory.如果你有Hibernate編程經驗, 你將實現SessionFactory Bean 負責去創建Session對象,通過Session對象處理 Transaction 和數據訪問. 現在同樣的SessionFactory Bean必須用Spring的方式進行配置如下,
<bean id="mySessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"> <property name="dataSource" ref="myDataSource"/> <property name="mappingResources"> <list> <value>com/xxxx/audit/pojo/Activitylog.hbm.xml</value> </list> </property> <property name="hibernateProperties"> <value>hibernate.dialect=org.hibernate.dialect.Oracle9Dialect</value> </property> </bean> |
當配置SessionFactory Bean時,我們已經給出兩個強制信息. 一個是data-source 信息包含訪問資料庫的細節;第二個是一個映射文件的列表,他包含了資料庫表和Java類之間的映射信息,我們在第2部分已經定義了他們,在『list』標誌中應用.
第三個重要的Spring Bean是Hibernate Template. 它提供了一個低級數據訪問和操作的包裝,精確地它包含以下方法:insert/delete/update/find資料庫中的數據,對Hibernate Template的配置唯一的變數是SessionFactory Bean對象如下所示:
<bean id="hibernateTemplate" class="org.springframework.orm.hibernate3.HibernateTemplate"> <property name="sessionFactory"> <ref bean="mySessionFactory"/> </property> </bean> |
的Bean定義是Dao類,是客戶化的類. 雖然此類必須定義在應用級,它能夠包含任意數量客戶數據訪問方法的封裝,雖然我們知道它是與資料庫交互的 Hibernate Template類,它將是一個Hibernate Template的理想引用.
<bean id="ActivitylogDao" class="javabeat.spring.hibernate.ActivitylogDao"> <property name="hibernateTemplate"> <ref bean="hibernateTemplate"/> </property> </bean> |
注意一個引用指向 ActivitylogDao類,它是我們以前討論過的.
3.5)定義ActivitylogDao class
如上所述, 這個ActivitylogDao 類能夠包含任意數量的方法供客戶訪問,這個類的設計有兩種選擇,第一種是此類能夠直接依賴Hibernate Template 對象訪問數據,它由IOC注入. 第二種是它你呢個夠利用Hibernate API做數據訪問,此類聲明如下:
ActivitylogDao.java package javabeat.spring.hibernate; import java.sql.SQLException; import org.hibernate.HibernateException; import org.hibernate.Session; import org.springframework.orm.hibernate3.HibernateCallback; import org.springframework.orm.hibernate3.HibernateTemplate; public class ActivitylogDao { private HibernateTemplate hibernateTemplate; public void setHibernateTemplate(HibernateTemplate hibernateTemplate){ this.hibernateTemplate = hibernateTemplate; } public HibernateTemplate getHibernateTemplate(){ return hibernateTemplate; } public Activitylog getActivitylog (final String id){ HibernateCallback callback = new HibernateCallback() { public Object doInHibernate(Session session) throws HibernateException,SQLException { return session.load(Activitylog.class, id); } }; return (Activitylog)hibernateTemplate.execute(callback); } public void saveOrUpdate(final Activitylog activitylog){ HibernateCallback callback = new HibernateCallback() { public Object doInHibernate(Session session) throws HibernateException,SQLException { session.saveOrUpdate(activitylog); return null; } }; hibernateTemplate.execute(callback); } } |
此類利用了Hibernate API (特別是Session對象) 用於數據訪問.引導Spring訪問 Hibernate API, 我們把邏輯細化,利用Hibernate API 融入Spring知道的著名介面中的特別著名的方法. It happens to be the HibernateCallback 介面使用方法doInHibernate() ,通過傳送一個Hibernate Session 實例, ActivitylogDao類我們已經定義了兩個方法:getActivitylog () and saveOrUpdate .使用Hibernate APIs, 我們定義了HibernateCallback中的代碼, doInHibernate() 方法和通知Spring 執行這些代碼 ,傳送介面引用HibernateTemplate.execute() 方法.
3.6) 客戶端測試程序
SpringHibernateTest.java package javabeat.spring.hibernate; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.xml.XmlBeanFactory; import org.springframework.core.io.FileSystemResource; import org.springframework.core.io.Resource; import org.springframework.orm.hibernate3.LocalSessionFactoryBean; public class SpringHibernateTest { public static void main(String[] args) { Resource resource = new FileSystemResource("./spring-hibernate.xml"); BeanFactory factory = new XmlBeanFactory(resource); Activitylog activitylog = new Activitylog (); activitylog.setId("123"); activitylog.setName("ABC"); activitylog.setTaskcode(「8000933120); activitylog.setTasktime(「2008 11 20 12:02:30 888888」); ActivitylogDao activitylogDao = (ActivitylogDao)factory.getBean( "activitylogDao"); activitylogDao.saveOrUpdate(activitylog); Activitylog actResult = activitylogDao.getActivitylog ("123"); System.out.println(actResult); } } |
, 我們運行客戶應用訪問測試數據,過程像這樣. 當方法BeanFactory.getBean("ActivitylogDao") 被調用, Spring 找到ActivitylogDao Bean 的指針. 它產生Hibernate Template 對象. 然後初始化Hibernate Template對象, 我們將看到一個Session Factory Bean對象被引用.然後當建立Session Factory Bean對象的時候, 將得到data-source 信息和資料庫表和Java類.
4)總結
本文討論了Spring 和Hibernate的集成. 既討論了需求也討論了它帶來的好處. 通過一個詳細的實例一步步清晰地演示了集成工作.
[火星人 ] 當Spring遇到Hibernate的時候已經有877次圍觀