首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Apache Geronimo 與 Spring 框架實戰(三):整合 Spring DAO、JDBC 與 iBATIS ORM

     編輯:Java 相關知識

本系列第三部分,將延續第二部分的骨架應用,引入 Spring JDBC、DAO 抽象層與 iBATIS SQL Maps,實現從 Apache Derby 資料庫動態讀取電話簿資料。您將見證依賴注入(IoC)的威力:僅修改 XML 組態即可切換資料來源,完全不動 Java 程式碼。

教學目標

  • 使用 Spring JDBC 模板簡化資料庫操作
  • 以 DAO 介面抽象資料存取邏輯
  • 整合 iBATIS SQL Maps 實現 ORM 映射
  • 體驗 Spring IoC 容器自動裝配資料來源與 DAO 實作
  • 透過 Geronimo 管理主控台建立資料庫結構

系統需求與準備

  • Spring Framework 1.2.8 (含相依套件)
  • Apache Geronimo 1.1 (內建 Derby)
  • iBATIS 2.1.7
  • Apache Commons DBCP & Pool
  • Apache Ant、Java 1.4.2+

資料模型與資料庫建置

領域物件

public class PhonebookEntry {
    private int entryID, rowID;
    private String fName, lName, homeNumber, workNumber, cellNumber, email;
    // getter/setter 略
}

資料庫結構(兩張表)

CREATE TABLE PB_ENTRY (
    ENTRY_ID INT NOT NULL PRIMARY KEY,
    ENTRY_FNAME VARCHAR(80), ENTRY_LNAME VARCHAR(80)
);

CREATE TABLE PB_DETAILS (
    ENTRY_ID INT NOT NULL, ROW_ID INT NOT NULL,
    HOME_NUMBER VARCHAR(20), WORK_NUMBER VARCHAR(20),
    CELL_NUMBER VARCHAR(20), EMAIL VARCHAR(200),
    PRIMARY KEY (ENTRY_ID, ROW_ID),
    FOREIGN KEY (ENTRY_ID) REFERENCES PB_ENTRY(ENTRY_ID)
);
Geronimo DB Manager 主控台
圖 1:Geronimo Web Console 資料庫管理介面

在 Geronimo 主控台 DB Manager 中建立 phonebook 資料庫,執行上述 DDL 並匯入範例資料(loadTables.sql)。

方案一:Spring JDBC + DAO 實作

DAO 介面

public interface IPhonebookDAO {
    List getPhonebookEntries() throws Exception;
}

JDBC 實作類

public class PhonebookJdbcDao extends JdbcDaoSupport implements IPhonebookDAO {
    public List getPhonebookEntries() throws Exception {
        JdbcTemplate jt = getJdbcTemplate();
        return jt.query(
            "SELECT * FROM PB_ENTRY A, PB_DETAILS B WHERE A.ENTRY_ID = B.ENTRY_ID AND A.ENTRY_ID <> 0",
            new RowMapperResultReader(new PhonebookRowMapper())
        );
    }
}

JdbcTemplate 自動處理連線建立/關閉、例外轉換,開發者專注 SQL 與映射邏輯。

Spring 組態:資料來源與 Bean 裝配

<bean id="pbJdbcDataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource" destroy-method="close">
    <property name="driverClassName" value="org.apache.derby.jdbc.EmbeddedDriver"/>
    <property name="url" value="jdbc:derby:phonebook"/>
    <property name="username" value="APP"/>
    <property name="password" value=""/>
</bean>

<bean id="phonebookDao" class="phonebook.dao.jdbc.PhonebookJdbcDao">
    <property name="dataSource" ref="pbJdbcDataSource"/>
</bean>

<bean id="phonebookJdbcDataProvider" class="phonebook.dao.PhonebookDataProvider">
    <property name="pbDao" ref="phonebookDao"/>
</bean>

web.xml 註冊 ApplicationContext

<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>/WEB-INF/ApplicationContext.xml</param-value>
</context-param>

服務層與 JSP 使用

public class PhonebookDataProvider {
    private IPhonebookDAO pbDao;
    public void setPbDao(IPhonebookDAO pbDao) { this.pbDao = pbDao; }
    public List getPhonebookEntries() throws Exception { return pbDao.getPhonebookEntries(); }
}
<%@ page import="phonebook.dao.*, java.util.List" %>
<%
    WebApplicationContext ctx = WebApplicationContextUtils.getWebApplicationContext(application);
    PhonebookDataProvider pb = (PhonebookDataProvider) ctx.getBean("phonebookJdbcDataProvider");
    List pbDetails = pb.getPhonebookEntries();
%>
<!-- 迭代 pbDetails 填充表格 -->
home-dao.jsp 運行結果
圖 2:JDBC DAO 版本運行畫面

方案二:iBATIS SQL Maps + Spring ORM

SQL Map 定義

<sqlMap namespace="Phonebook">
    <select id="getPhonebookEntries" resultClass="phonebook.dao.PhonebookEntry">
        SELECT A.ENTRY_ID as entryID, A.ENTRY_FNAME as fName, A.ENTRY_LNAME as lName,
               B.ROW_ID as rowID, B.HOME_NUMBER as homeNumber, B.WORK_NUMBER as workNumber,
               B.CELL_NUMBER as cellNumber, B.EMAIL as email
        FROM PB_ENTRY A, PB_DETAILS B
        WHERE A.ENTRY_ID = B.ENTRY_ID AND A.ENTRY_ID != 0
    </select>
</sqlMap>

SQL Map 組態檔

<sqlMapConfig>
    <settings cacheModelsEnabled="true" enhancementEnabled="true" lazyLoadingEnabled="true"
              maxRequests="32" maxSessions="10" maxTransactions="5" useStatementNamespaces="false"/>
    <sqlMap resource="/phonebook/dao/orm/Phonebook.xml"/>
</sqlMapConfig>

ORM DAO 實作

public class SqlMapPhonebookDao extends SqlMapClientDaoSupport implements IPhonebookDAO {
    public List getPhonebookEntries() throws Exception {
        return getSqlMapClientTemplate().queryForList("getPhonebookEntries", null);
    }
}

Spring 組態:切換資料來源展現 IoC 魔力

<!-- 使用 Commons DBCP 連線池 -->
<bean id="pbOrmDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
    <property name="driverClassName" value="org.apache.derby.jdbc.EmbeddedDriver"/>
    <property name="url" value="jdbc:derby:phonebook"/>
    <property name="username" value="APP"/>
    <property name="password" value=""/>
</bean>

<bean id="sqlMapClient" class="org.springframework.orm.ibatis.SqlMapClientFactoryBean">
    <property name="configLocation" value="/META-INF/sqlmap-config.xml"/>
    <property name="dataSource" ref="pbOrmDataSource"/>
</bean>

<bean id="phonebookOrmDao" class="phonebook.dao.orm.SqlMapPhonebookDao">
    <property name="sqlMapClient" ref="sqlMapClient"/>
</bean>

<bean id="phonebookOrmDataProvider" class="phonebook.dao.PhonebookDataProvider">
    <property name="pbDao" ref="phonebookOrmDao"/>
</bean>

整合驗證:同一 iBATIS DAO 使用 JDBC 資料來源

只需修改一行組態,讓 iBATIS 共用 JDBC 定義的 DataSource:

<bean id="sqlMapClient" class="org.springframework.orm.ibatis.SqlMapClientFactoryBean">
    <property name="configLocation" value="/META-INF/sqlmap-config.xml"/>
    <property name="dataSource" ref="pbJdbcDataSource"/> <!-- 改為引用 JDBC DataSource -->
</bean>

重新部署後訪問 home-orm.jsp,資料同樣正確顯示,證明資料來源完全解耦。

Spring 持久層優勢總結

  • 完整抽象連線管理,杜絕資源洩漏
  • 統一例外層級,將 SQLException 轉為有意義的 Spring DAO 例外
  • 支援多種 ORM(Hibernate、JDO、iBATIS、OJB),輕鬆切換
  • 聲明式事務管理(下一部分詳細介紹)
  • 極易單元測試:替換 DataSource 即可隔離測試

下一步預告

第四部分將引入 Spring AOP 實現方法攔截追蹤,並展示聲明式事務管理與 Spring Web Flow 宣告式流程定義。

下載資源

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved