首先建立支援二進位欄位的 BookUser 表:
CREATE TABLE [BookUser] (
[UserID] INT IDENTITY(1,1) NOT NULL PRIMARY KEY,
[UserName] VARCHAR(50) NOT NULL,
[Title] NVARCHAR(50) NOT NULL,
[Guid] UNIQUEIDENTIFIER NOT NULL DEFAULT NEWID(),
[BirthDate] DATETIME NOT NULL,
[Description] NTEXT NOT NULL,
[Photo] IMAGE NULL,
[Other] VARCHAR(50) NULL DEFAULT '預設值'
);
建立新增使用者預存程序 InsertUser,驗證 Title 唯一性並回傳自增 ID:
CREATE PROCEDURE InsertUser
@UserName VARCHAR(50),
@Title VARCHAR(255),
@Guid UNIQUEIDENTIFIER,
@BirthDate DATETIME,
@Description NTEXT,
@Photo IMAGE,
@Other NVARCHAR(50),
@UserID INT OUTPUT
AS
BEGIN
SET NOCOUNT ON;
IF EXISTS (SELECT UserID FROM BookUser WHERE Title = @Title)
RETURN 0; -- 唯一性驗證失敗
INSERT INTO BookUser (UserName, Title, Guid, BirthDate, Description, Photo, Other)
VALUES (@UserName, @Title, @Guid, @BirthDate, @Description, @Photo, @Other);
SET @UserID = @@IDENTITY;
RETURN 1; -- 成功
END
<%@ page language="java" import="java.util.*,java.sql.*,java.io.*" pageEncoding="UTF-8"%>
<%
// 1. 載入 Microsoft 官方 JDBC 驅動 (需從微軟官網下載)
Class.forName("com.microsoft.jdbc.sqlserver.SQLServerDriver");
// 2. 連線字串:注意 useUnicode=true&characterEncoding=UTF-8 避免中文亂碼
String url = "jdbc:microsoft:sqlserver://localhost:1433;DatabaseName=owend;user=sa;password=;useUnicode=true;characterEncoding=UTF-8";
// 3. 預存程序呼叫語法:{? = call ProcName(?,?,...)} 第一個 ? 對應 RETURN 值
String sql = "{? = call InsertUser(?,?,?,?,?,?,?,?)}";
Connection conn = null;
CallableStatement cmd = null;
try {
conn = DriverManager.getConnection(url);
cmd = conn.prepareCall(sql);
// 4. 參數綁定(索引從 1 開始)
cmd.registerOutParameter(1, Types.INTEGER); // RETURN 值
cmd.setString(2, "mengxianhui"); // @UserName
cmd.setString(3, "孟憲會2"); // @Title
cmd.setString(4, UUID.randomUUID().toString()); // @Guid
cmd.setDate(5, Date.valueOf("2009-07-04")); // @BirthDate
cmd.setString(6, "【孟子E章】"); // @Description
// 5. 二進位檔案處理:使用 setBinaryStream
String filePath = application.getRealPath("") + "/test/logo.gif";
FileInputStream fis = new FileInputStream(filePath);
cmd.setBinaryStream(7, fis, fis.available()); // @Photo (IMAGE)
cmd.setString(8, "555"); // @Other
cmd.registerOutParameter(9, Types.INTEGER); // @UserID OUTPUT
// 6. 執行
cmd.execute();
// 7. 取得結果
int returnValue = cmd.getInt(1); // RETURN 值
int userID = cmd.getInt(9); // OUTPUT 參數
if (returnValue == 1) {
out.println("<li>新增成功!");
out.println("<li>UserID = " + userID);
out.println("<li>ReturnValue = " + returnValue);
} else {
out.println("<li>新增失敗:Title 已存在");
}
fis.close();
} catch (Exception ex) {
out.println("<li>錯誤:" + ex.getMessage());
ex.printStackTrace();
} finally {
// 8. 資源釋放(逆序關閉)
if (cmd != null) try { cmd.close(); } catch (Exception ignore) {}
if (conn != null) try { conn.close(); } catch (Exception ignore) {}
}
%>
| 技術點 | 處理方式 | 注意事項 |
|---|---|---|
| JDBC 驅動 | Microsoft 官方 sqljdbc.jar | 舊版用 com.microsoft.jdbc.sqlserver.SQLServerDriver |
| 預存程序語法 | {? = call Proc(?,?)} | 第一個 ? 必須對應 RETURN 值 |
| OUTPUT 參數 | registerOutParameter(index, Types.INTEGER) | 索引須包含 RETURN 值位置 |
| 二進位資料 | setBinaryStream(index, InputStream, length) | IMAGE/VARBINARY(MAX) 欄位適用 |
| UNIQUEIDENTIFIER | setString(UUID.toString()) | Java UUID 需轉字串傳入 |
| 中文編碼 | 連線字串加 useUnicode=true&characterEncoding=UTF-8 | 資料庫欄位用 NVARCHAR/NTEXT |
| 資源管理 | finally 區塊關閉 Statement → Connection | 避免連線洩漏導致資料庫拒絕服務 |
掌握此完整流程,即可在 Java Web 專案中穩健處理預存程序呼叫、二進位檔案存儲與輸出參數接收。