JDBC `Connection.createStatement()` 重載方法允許指定 `ResultSet` 的**類型**與**並發性**,決定游標可滾動性、敏感性及可更新性。本文系統講解三種類型、兩種並發性的組合差異、適用場景與代碼示例。
Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException;
| 常量 | 值 | 游標特性 | 對外部修改可見性 | 典型用途 |
|---|---|---|---|---|
TYPE_FORWARD_ONLY | 1003 | 僅能向前移動(`next()`),不可回滾 | 不可見(快照) | 預設、大數據流式讀取、高性能 |
TYPE_SCROLL_INSENSITIVE | 1004 | 可向前/向後、絕對/相對定位(`first()`、`last()`、`absolute(n)`、`relative(n)`) | 不可見(開啟時快照) | 分頁查詢、需隨機訪問行 |
TYPE_SCROLL_SENSITIVE | 1005 | 可滾動定位 | **可見**(實時反映他人提交的增刪改) | 協作環境、實時監控 |
| 常量 | 值 | 含義 | 支援操作 |
|---|---|---|---|
CONCUR_READ_ONLY | 1007 | 只讀(預設) | 僅 `getXxx()` |
CONCUR_UPDATABLE | 1008 | 可更新 | `updateXxx()`、`insertRow()`、`deleteRow()`、`refreshRow()` |
| 類型 \ 並發性 | READ_ONLY | UPDATABLE |
|---|---|---|
| FORWARD_ONLY | ✅ 普遍支援 | ⚠️ 部份資料庫支援(MySQL 支援) |
| SCROLL_INSENSITIVE | ✅ 普遍支援 | ⚠️ 需主鍵、資料庫支援 |
| SCROLL_SENSITIVE | ⚠️ 部分支援 | ❌ 極少支援 |
MySQL (Connector/J) 實測:
- `TYPE_FORWARD_ONLY` + `CONCUR_UPDATABLE` ✅
- `TYPE_SCROLL_INSENSITIVE` + `CONCUR_UPDATABLE` ✅ (需主鍵)
- `TYPE_SCROLL_SENSITIVE` 任何並發性 ❌ 退化為 INSENSITIVE
Statement stmt = conn.createStatement(
ResultSet.TYPE_SCROLL_INSENSITIVE,
ResultSet.CONCUR_READ_ONLY
);
ResultSet rs = stmt.executeQuery("SELECT * FROM users");
rs.last(); // 移至最後一行
int total = rs.getRow(); // 獲取總行數
rs.absolute((page-1)*pageSize + 1); // 定位到頁首行
// 讀取 pageSize 行...
Statement stmt = conn.createStatement(
ResultSet.TYPE_SCROLL_INSENSITIVE, // 或 FORWARD_ONLY
ResultSet.CONCUR_UPDATABLE
);
ResultSet rs = stmt.executeQuery("SELECT id, name, balance FROM accounts WHERE id=1");
if (rs.next()) {
rs.updateDouble("balance", rs.getDouble("balance") + 100);
rs.updateRow(); // 提交修改到資料庫
}
rs.moveToInsertRow();
rs.updateString("name", "New User");
rs.updateDouble("balance", 0);
rs.insertRow();
rs.moveToCurrentRow();
`createStatement(type, concurrency)` 靈活控制 `ResultSet` 行為:
理解這些選項,能在遺留系統維護或特殊需求下做出正確選擇;新專案優先考慮 SQL 層面解決分頁與更新。