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

SQL Server 2000 JDBC 分頁解決方案:遊標存儲過程與多 ResultSet 處理

     編輯:關於SqlServer

背景與挑戰

  • SQL Server 2000 **無 `ROW_NUMBER()`、`OFFSET/FETCH`**,分頁需自行實作。
  • JDBC 需處理**單次呼叫返回多個 `ResultSet`** 的情況 (存儲過程多結果集)。
  • 專案類徑需包含:`msbase.jar`、`mssqlserver.jar`、`msutil.jar` (SQL 2000 官方驅動)。**切勿混用 SQL 2005 `sqljdbc.jar`**,會報錯。

分頁存儲過程:系統遊標法


IF NOT EXISTS (SELECT * FROM dbo.sysobjects 
    WHERE id = OBJECT_ID(N'[dbo].[Pr_QueryByPage]') AND OBJECTPROPERTY(id,N'IsProcedure') = 1)
BEGIN
    EXEC dbo.sp_executesql @statement = N'
    CREATE PROCEDURE [dbo].[Pr_QueryByPage]
        @sqlstr NVARCHAR(4000),   -- 查詢 SQL (不含 ORDER BY)
        @currentpage INT,         -- 第幾頁 (1-based)
        @pagesize INT             -- 每頁筆數
    AS
    BEGIN
        SET NOCOUNT ON;
        DECLARE @P1 INT, @rowcount INT;
        -- 開啟遊標 (FORWARD_ONLY, READ_ONLY)
        EXEC sp_cursoropen @P1 OUTPUT, @sqlstr, @scrollopt=1, @ccopt=1, @rowcount=@rowcount OUTPUT;
        -- 返回總頁數、總筆數
        SELECT CEILING(1.0 * @rowcount / @pagesize) AS TotalPage, @rowcount AS RowCount;
        -- 計算游標提取起始位置
        SET @currentpage = (@currentpage - 1) * @pagesize + 1;
        -- 提取指定範圍
        EXEC sp_cursorfetch @P1, 16, @currentpage, @pagesize;
        -- 關閉遊標
        EXEC sp_cursorclose @P1;
        SET NOCOUNT OFF;
    END';
END
GO

關鍵系統預存程序

  • `sp_cursoropen`:開啟伺服器端遊標,返回遊標控制代碼 `@P1` 與總筆數 `@rowcount`。
  • `sp_cursorfetch`:從遊標提取指定位置/筆數。參數 `16` = `FETCH_NEXT` + `FETCH_RELATIVE` 組合 (文獻常見值)。
  • `sp_cursorclose`:釋放遊標資源。

⚠️ **效能提示**:遊標法需建立臨時結果集,**不如 `TOP` 配合鍵值法效能好**,但可直接返回總筆數,免去第二次 `COUNT(*)` 查詢。

JDBC 多 ResultSet 處理模式

呼叫 `Pr_QueryByPage` 返回 **三個 ResultSet**:

  1. 空結果集 (查詢結構無資料)
  2. 分頁資訊:`TotalPage`, `RowCount`
  3. 實際分頁資料

CallableStatement cs = conn.prepareCall("exec Pr_QueryByPage 'SELECT * FROM ckdmzd', 1, 10");
boolean hasResultSet = cs.execute();  // true = 有 ResultSet

if (hasResultSet) {
    ResultSet rs = cs.getResultSet();  // 第 1 個:空結構
    
    // 第 2 個:分頁資訊
    if (cs.getMoreResults()) {
        rs = cs.getResultSet();
        while (rs.next()) {
            String pageCount = rs.getString(1);
            String recordCount = rs.getString(2);
            // 解析總頁數、總筆數
        }
    }
    
    // 第 3 個:分頁資料
    if (cs.getMoreResults()) {
        rs = cs.getResultSet();
        while (rs.next()) {
            // 處理分頁資料列
        }
    }
}

關鍵 API

  • `Statement.execute()`:返回 `true` 表示有 `ResultSet`,`false` 表示更新筆數。
  • `getResultSet()`:取得當前 `ResultSet`。
  • `getMoreResults()`:移動到下一個 `ResultSet`,返回 `true` 表示存在。

此模式適用於 `PreparedStatement`、`CallableStatement`、`Statement` 所有 JDBC 執行介面。

方案總結與選型建議

方案優點缺點適用場景
系統遊標存儲過程 (本文)單次呼叫得總筆數+分頁資料、封裝邏輯遊標開銷大、深分頁慢、佔用 tempdbSQL 2000 既有系統、需總筆數、併發中低
雙查詢法 (COUNT + TOP 鍵值)效能佳、標準 SQL兩次往返、需應用層組裝新開發、高併發、深分頁
臨時表/表變數分頁邏輯直觀寫入 tempdb、鎖爭用複雜條件、一次性報表

遷移提示:SQL Server 2005+

升級至 SQL 2005 後,**首選 `ROW_NUMBER()` CTE 或 `OFFSET/FETCH` (2012+)**,棄用遊標分頁。JDBC 驅動同步升級為 `sqljdbc4.jar` (JDBC 4.0),支援 `getGeneratedKeys()`、表值參數等現代特性。

小結

SQL Server 2000 JDBC 分頁,系統遊標存儲過程 + `CallableStatement` 多 `ResultSet` 處理是經典解法。理解 `sp_cursoropen/fetch/close` 機制與 JDBC 多結果集 API,可維護舊系統並平滑遷移至現代分頁模式。

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