JSP 主責動態頁面渲染,不宜混雜複雜 Java 邏輯 (Scriptlet 已棄用)。JSTL SQL 標籤庫 (sql.tld) 提供宣告式資料庫操作,實現資料存取與展示分離,適合中小型專案或原型快速開發。
<sql:setDataSource> 建立資料源<%@ taglib prefix="sql" uri="https://java.sun.com/jsp/jstl/sql" %>
<sql:setDataSource
var="ds"
driver="oracle.jdbc.OracleDriver"
url="jdbc:oracle:thin:@localhost:1521:ORCL"
user="scott"
password="tiger"
scope="application" />
com.mysql.cj.jdbc.Driver, PostgreSQL: org.postgresql.Driver)。<c:choose> 根據部署配置動態選擇驅動/URL。application 共享連線池 (需配合 javax.sql.DataSource 實現),request/session 適用輕量場景。<sql:query> 執行查詢<sql:query dataSource="${ds}" var="result" maxRows="50" startRow="${param.start}">
SELECT product_id, product_name, price
FROM products
WHERE category_id = ? AND status = 'ACTIVE'
<sql:param value="${param.categoryId}" />
</sql:query>
<c:forEach var="row" items="${result.rows}">
${row.product_name} - ${row.price} <br/>
</c:forEach>
| 實踐 | 說明 | 範例 |
|---|---|---|
| 必須先建立連線 | sql:query 依賴 dataSource 屬性或 setDataSource 變數 | dataSource="${ds}" |
| 使用參數化查詢 | 防 SQL 注入、利用資料庫執行計劃緩存、提升效能 | <sql:param value="..."/> 對應 SQL 中 ? |
| 大小寫敏感度 | Oracle 欄位名不區分大小寫,值區分;MySQL 依 collation;統一用資料庫實際欄位名 | ${row.PRODUCT_NAME} vs ${row.product_name} |
| 分頁預設參數 | 避免無條件全表掃描;maxRows 限制單頁筆數,startRow 配合頁碼參數 | maxRows="50" startRow="${(param.page-1)*50}" |
| 業務預設值 | 銷售單預設今日、商品預設最新 50 筆,減少資料庫壓力 | WHERE order_date = CURDATE() |
<sql:update><sql:update dataSource="${ds}" var="count">
UPDATE inventory SET stock = stock - ? WHERE product_id = ?
<sql:param value="${param.qty}" />
<sql:param value="${param.pid}" />
</sql:update>
<c:if test="${count > 0}">扣減庫存成功</c:if>
JSTL SQL 適合簡單 CRUD、原型、報表類頁面。隨著專案增長,建議遷移至:
context.xml 定義 DataSource,JNDI 查找注入。@Transactional 宣告式事務,JSTL SQL 無事務支援。