CREATE TABLE mytest (
id INT NOT NULL,
name VARCHAR(50) COLLATE Chinese_PRC_CI_AS NOT NULL,
phone VARCHAR(13) COLLATE Chinese_PRC_CI_AS NULL,
addr VARCHAR(50) COLLATE Chinese_PRC_CI_AS NULL
) ON [PRIMARY];
GO
CREATE PROCEDURE get_info
AS
BEGIN
SELECT * FROM mytest;
END;
GO
注意:原範例程序參數未使用,簡化為無參數查詢。實務中應依需求設計參數化查詢。
INSERT INTO mytest (id, name, phone, addr) VALUES
(1, 'cc', '1234', 'cs'),
(2, 'dd', '4567', 'bj'),
(3, 'ee', '1245', 'ca');
<%@ page language="java" pageEncoding="UTF-8"
import="java.sql.*,javax.sql.DataSource" %>
<%@ taglib uri="https://jakarta.apache.org/struts/tags-bean" prefix="bean" %>
<%@ taglib uri="https://jakarta.apache.org/struts/tags-html" prefix="html" %>
<%@ taglib uri="https://jakarta.apache.org/struts/tags-logic" prefix="logic" %>
<%@ taglib uri="https://jakarta.apache.org/struts/tags-tiles" prefix="tiles" %>
預存程序呼叫測試
預存程序呼叫測試
<%
// 連線參數建議從 JNDI DataSource 取得,此處為示範直接寫死
String username = "sa";
String password = "123456";
String url = "jdbc:microsoft:sqlserver://192.168.1.112:1433;DatabaseName=test";
Connection conn = null;
CallableStatement cstmt = null;
ResultSet rs = null;
try {
Class.forName("com.microsoft.jdbc.sqlserver.SQLServerDriver").newInstance();
conn = DriverManager.getConnection(url, username, password);
// 正確呼叫預存程序的方式:使用 CallableStatement
String sql = "{CALL get_info}";
cstmt = conn.prepareCall(sql);
rs = cstmt.executeQuery();
// 輸出結果表格
%>
ID Name Phone Address
<%
while (rs.next()) {
%>
<%= rs.getString("id") %>
<%= rs.getString("name") %>
<%= rs.getString("phone") %>
<%= rs.getString("addr") %>
<%
}
%>
<%
} catch (Exception e) {
out.println("錯誤: " + e.getMessage() + "
");
e.printStackTrace();
} finally {
// 依序關閉資源,避免洩漏
try { if (rs != null) rs.close(); } catch (Exception ignored) {}
try { if (cstmt != null) cstmt.close(); } catch (Exception ignored) {}
try { if (conn != null) conn.close(); } catch (Exception ignored) {}
}
%>
| 技術點 | 說明 |
|---|---|
| CallableStatement | 專門用於呼叫預存程序的 JDBC 介面,支援輸入/輸出參數、結果集 |
SQL 語法 {CALL proc_name} | JDBC 標準逃逸語法,跨資料庫可移植 |
| prepareCall vs createStatement | 預存程序必須用 prepareCall;createStatement 只能執行直接 SQL |
| 資源關閉順序 | ResultSet → Statement/CallableStatement → Connection,反向建立順序 |
| 連線池 | 生產環境務必使用 JNDI DataSource (DBCP/HikariCP/C3P0),避免頻繁建立連線 |
Statement stmt = conn.createStatement(); stmt.executeQuery("{CALL get_info}"); → 錯誤,必須用 CallableStatement。com.microsoft.jdbc.sqlserver.SQLServerDriver;SQL Server 2005+ 建議用 com.microsoft.sqlserver.jdbc.SQLServerDriver (sqljdbc.jar)。characterEncoding=UTF-8 一致。
-- 預存程序
CREATE PROCEDURE get_info_by_name @name VARCHAR(50)
AS
SELECT * FROM mytest WHERE name = @name;
GO
-- JSP 呼叫
String sql = "{CALL get_info_by_name(?)}";
cstmt = conn.prepareCall(sql);
cstmt.setString(1, "cc");
rs = cstmt.executeQuery();
掌握 CallableStatement 標準用法,是 Java 應用整合 SQL Server 預存程序的基石。