當 SQL 參數為大型文本(超過 VARCHAR 長度限制)或需以流式傳輸避免記憶體峰值時,可使用 PreparedStatement.setAsciiStream() 將 ASCII 字元流綁定至 LONGVARCHAR/CLOB 參數。
| 方法 | 適用資料型別 | 說明 |
|---|---|---|
setAsciiStream(int idx, InputStream in, int len) | LONGVARCHAR / CLOB | ASCII 字元流,1 byte = 1 char |
setCharacterStream(int idx, Reader in, int len) | LONGVARCHAR / CLOB | 字元流(支援 Unicode),JDBC 2.0+ 推薦 |
setBinaryStream(int idx, InputStream in, int len) | LONGVARBINARY / BLOB | 二進位流(圖片、檔案) |
len 參數告知驅動程式流長度,部分資料庫要求準確,否則可能拋例外。
public class ParameterQueryDemo {
public static void main(String[] args) {
String url = "jdbc:odbc:studentDSN"; // 舊式 ODBC Bridge,現建議用原生驅動
String sql = "SELECT * FROM student WHERE age = ?";
try (Connection conn = DriverManager.getConnection(url, "sa", "");
PreparedStatement ps = conn.prepareStatement(sql);
FileInputStream fis = new FileInputStream("d:/java/usefile.txt")) {
// 1. 設定 ASCII 流參數(假設檔案內容為年齡字串,長度 2)
ps.setAsciiStream(1, fis, 2);
// 2. 執行查詢
try (ResultSet rs = ps.executeQuery()) {
while (rs.next()) {
String name = rs.getString("name");
String age = rs.getString("age");
int cno = rs.getInt("classno");
String addr = rs.getString("address");
String tel = rs.getString("telephone");
System.out.printf("%s %s %d %s %s%n", name, age, cno, addr, tel);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
Class.forName()。DriverManager.getConnection(),建議搭配連線池 (HikariCP/Druid)。setAsciiStream(1, fis, length),索引從 1 起算。next() 游標前移,getXxx() 取欄位值。Connection/Statement/ResultSet/InputStream。| 問題 | 解決方案 |
|---|---|
| 流長度不準確導致例外 | 若無法預知長度,改用 setCharacterStream 無長度版本(JDBC 4.0+)或先讀入記憶體 |
| 大物件 (LOB) 處理 | 優先用 setClob()/setBlob() 或資料庫專屬 API (Oracle oracle.sql.CLOB) |
| 編碼不一致 | ASCII 流僅支援單字節字符,中文請用 setCharacterStream + UTF-8 Reader |
| 連線洩漏 | 務必使用 try-with-resources 或 finally 區塊關閉所有資源 |
jdbcTemplate.query(sql, ps -> ps.setAsciiStream(1, fis, len), rowMapper) 簡化樣板碼。<parameter jdbcType="LONGVARCHAR" typeHandler="AsciiStreamTypeHandler"> 宣告式配置。@Lob String content 自動映射 CLOB。