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

JDBC 操作 SQL Server 2000 大字段(IMAGE/TEXT)完整實戰代碼

     編輯:Java 相關知識

早期 SQL Server 2000 中存儲二進制文件(圖片、文檔)需使用 IMAGE 類型(TEXT 用於大文本,但與二進制流不兼容)。本文提供基於 JDBC-ODBC 橋接器的完整存取示例,雖技術棧較老,但核心 PreparedStatement.setBinaryStream/getBinaryStream 模式在現代 JDBC 中依然通用。

數據庫表結構設計

CREATE TABLE FileStorage (
    id CHAR(10) PRIMARY KEY,      -- 業務主鍵
    data IMAGE                    -- 二進制數據,最大 2GB
    -- 注意:不可使用 TEXT 類型存二進制,TEXT 為字符流類型
);

核心存取工具類實現

import java.io.*;
import java.sql.*;

public class SqlServerBlobHandler {

    private static final String URL = "jdbc:odbc:LW";  // 系統 DSN 名稱
    private static final String INSERT_SQL = "INSERT INTO FileStorage (id, data) VALUES (?, ?)";
    private static final String SELECT_SQL = "SELECT data FROM FileStorage WHERE id = ?";

    /**
     * 文件寫入數據庫
     * @param filePath 本地文件路徑
     * @param id 業務主鍵
     */
    public void insertFile(String filePath, String id) {
        File file = new File(filePath);
        try (Connection conn = DriverManager.getConnection(URL);
             PreparedStatement ps = conn.prepareStatement(INSERT_SQL);
             FileInputStream fis = new FileInputStream(file)) {

            Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");  // JDK 8 前可用

            ps.setString(1, id);
            // 關鍵:使用 setBinaryStream 流式寫入,避免大文件 OOM
            ps.setBinaryStream(2, fis, (int) file.length());
            ps.executeUpdate();
            System.out.println("文件存入成功: " + id);

        } catch (Exception e) {
            throw new RuntimeException("文件存入失敗: " + id, e);
        }
    }

    /**
     * 從數據庫讀取文件到本地
     * @param id 業務主鍵
     * @param destPath 目標保存路徑
     */
    public void extractFile(String id, String destPath) {
        try (Connection conn = DriverManager.getConnection(URL);
             PreparedStatement ps = conn.prepareStatement(SELECT_SQL);
             ResultSet rs = ps.executeQuery()) {

            ps.setString(1, id);
            if (rs.next()) {
                try (InputStream bis = rs.getBinaryStream("data");
                     FileOutputStream fos = new FileOutputStream(destPath)) {

                    byte[] buffer = new byte[8192];
                    int len;
                    while ((len = bis.read(buffer)) != -1) {
                        fos.write(buffer, 0, len);
                    }
                    System.out.println("文件提取成功: " + destPath);
                }
            } else {
                System.out.println("未找到記錄: " + id);
            }

        } catch (Exception e) {
            throw new RuntimeException("文件提取失敗: " + id, e);
        }
    }

    public static void main(String[] args) {
        SqlServerBlobHandler handler = new SqlServerBlobHandler();
        // 測試存入
        handler.insertFile("D:\\test1.txt", "0004");
        // 測試提取
        handler.extractFile("0004", "D:\\restored_test1.txt");
    }
}

關鍵技術點解析

1. 流式處理避免內存溢出

  • 寫入:ps.setBinaryStream(index, inputStream, length) 分塊傳輸,不將整文件載入內存
  • 讀取:rs.getBinaryStream(column) 獲取輸入流,緩衝區循環寫出
  • 緩衝區大小 8KB 平衡內存與系統調用開銷

2. JDBC-ODBC 橋接器配置

  1. 控制面板 → 管理工具 → 數據源 (ODBC) → 系統 DSN → 添加
  2. 選擇 "SQL Server" 驅動,配置服務器、認證、默認數據庫
  3. DSN 名稱 (如 LW) 需與代碼 jdbc:odbc:LW 一致

警告: sun.jdbc.odbc.JdbcOdbcDriver 在 JDK 8 中被移除,現代項目請使用 Microsoft 官方 mssql-jdbc 驅動:

// 現代驅動配置
Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
String url = "jdbc:sqlserver://localhost:1433;databaseName=TestDB;user=sa;password=123456";

3. 大文本 (CLOB/TEXT) 處理差異

// 寫入 CLOB
ps.setCharacterStream(2, new FileReader(file), (int) file.length());

// 讀取 CLOB
Reader reader = rs.getCharacterStream("data");
// 或 rs.getClob("data").getCharacterStream()

完整測試類(含線程封裝)

原文採用線程封裝讀取文件再寫入,現代寫法建議直接流式處理。若需異步,可使用 CompletableFuture 或線程池:

ExecutorService executor = Executors.newFixedThreadPool(4);
executor.submit(() -> handler.insertFile("large_video.mp4", "VID_001"));

常見問題排查

錯誤現象原因解決
Data type mismatch用 TEXT 列存二進制 / 用 IMAGE 存文本流類型匹配:IMAGE↔BinaryStream, TEXT↔CharacterStream
Stream closedResultSet/Connection 關閉前讀取流在 try-with-resources 內完成流讀寫
Heap Space OOM用 getBytes()/String 載入大文件堅持使用 Stream API 分塊處理
ClassNotFound: JdbcOdbcDriverJDK 8+ 移除橋接器遷移至 mssql-jdbc 驅動

掌握 setBinaryStream/getBinaryStream 流式模式,即可應對任意版本 SQL Server 及主流數據庫的大對象存取需求。

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