傳統 DriverManager.getConnection(url, user, pwd) 方式存在兩大痛點:
JDBC 2.0 引入 javax.sql.DataSource 接口,配合 JNDI (Java Naming and Directory Interface) 命名服務,完美解決上述問題:程式碼僅持有邏輯名稱,具體連線參數由容器/管理員統一管理。
DataSource 封裝了建立連線所需的所有屬性(9 標準屬性 + 廠商擴展屬性):
| 標準屬性 | 類型 | 說明 |
|---|---|---|
| databaseName | String | 資料庫 SID |
| serverName | String | 伺服器主機名/IP |
| portNumber | int | 埠號(預設 1521) |
| user / password | String | 登入憑證(注意:無 getPassword(),增強安全性) |
| networkProtocol | String | 通訊協議(TCP/IPC) |
| dataSourceName | String | 實現類名稱 |
| description | String | 描述資訊 |
所有 setter/getter 均為 synchronized,保證線程安全。Oracle 等廠商提供擴展實現(OracleDataSource),新增 driverType(thin/oci8/kprb)、url、tnsEntry 等屬性,支援更靈活的連線描述方式。
JNDI 將「名稱」映射到「物件/服務」。對 JDBC 而言,它是 DataSource 物件的註冊與查找中心。常見服務提供者:
com.sun.jndi.fscontext.RefFSContextFactory):開發測試用。java:comp/env, WebLogic, WildFly 等):企業級標準。OracleDataSource ods = new OracleDataSource();
ods.setDriverType("thin");
ods.setServerName("db-host");
ods.setPortNumber(1521);
ods.setDatabaseName("ORCL");
ods.setUser("app_user");
ods.setPassword("secret"); // 僅在程式碼中出現一次,或從加密配置讀取
Connection conn = ods.getConnection(); // 直接獲取連線
適用於獨立應用、單元測試、微服務輕量級部署。注意屬性優先級規則:url 設定後其它屬性失效;tnsEntry 設定後網路屬性失效。
步驟 1:容器配置 DataSource (以 Tomcat context.xml 為例)
<Resource name="jdbc/MyDB"
auth="Container"
type="javax.sql.DataSource"
driverClassName="oracle.jdbc.OracleDriver"
url="jdbc:oracle:thin:@db-host:1521:ORCL"
username="app_user" password="secret"
maxTotal="20" maxIdle="10" maxWaitMillis="-1"/>
步驟 2:程式碼查找使用
Context ctx = new InitialContext();
DataSource ds = (DataSource) ctx.lookup("java:comp/env/jdbc/MyDB");
Connection conn = ds.getConnection(); // 從連線池獲取
// 業務邏輯...
conn.close(); // 歸還連線池,非物理關閉
優勢:零硬編碼、連線池由容器專業管理、支援熱更新配置、便於 DBA 統一維護。
Connection 非線程安全,嚴禁跨線程共用同一連線。OracleDataSource 實現 Serializable 與 Referenceable,支援 RMI 遠端傳遞與 JNDI 存儲引用。javax.sql.DataSource 實現的密碼加密機制,或使用 Vault/Consul 等外部密碼管理服務。SELECT 1 FROM DUAL)。DataSource + JNDI 是 Java EE 資料庫存取的基石模式。它將資源配置與業務邏輯解耦,實現了安全性、可移植性與可維護性的三重提升。現代雲原生架構下,雖然配置中心取代了傳統 JNDI,但「邏輯名稱換取實體資源」的核心設計哲學始終未變。