當你已掌握 Java 基礎語法與物件導向概念,下一步便是學習如何讓程式與外部世界互動。本章將帶你探索三項企業級開發的基石技術:JDBC 資料庫連線、多執行緒平行處理,以及JavaBeans 元件架構。透過本章學習,你將具備開發資料驅動應用、高併發程式與可重用元件的核心能力。
在資訊時代,資料庫是系統的心臟。市面上存在 Oracle、SQL Server、MySQL、PostgreSQL 等眾多資料庫產品,雖然都支援 SQL 標準,但各家的原生 API、連線協定、資料型別映射卻大相逕庭。若應用程式直接依賴特定資料庫的 API,將導致程式碼高度耦合,移植極其困難。
Microsoft 早期推出 ODBC (Open Database Connectivity),提供統一的 C 語言介面,透過驅動程式管理器屏蔽底層差異。然而 ODBC 專為 C 設計,Java 難以直接呼叫;且 ODBC 屬 Microsoft 標準,Sun 公司(現 Oracle)為了 Java 的跨平台特性,於 1996 年推出 JDBC (Java Database Connectivity)。
JDBC 繼承 ODBC 設計精髓,同樣基於 X/Open SQL CLI (Call Level Interface) 規範。為利用既有 ODBC 驅動,Sun 更提供 JDBC-ODBC Bridge(橋接器),讓 Java 可透過 ODBC 連線資料庫。
所有 JDBC 類別位於 java.sql 套件。核心類別包括:
DriverManager:驅動管理器,負責註冊驅動、建立連線Connection:資料庫連線物件,代表一個 SessionStatement / PreparedStatement / CallableStatement:執行靜態 SQL、參數化 SQL、預存程序ResultSet:查詢結果集,提供游標式資料存取DatabaseMetaData / ResultSetMetaData:取得資料庫與結果集結構描述// 1. 載入驅動(JDBC 4.0+ 可省略,自動發現)
Class.forName("com.mysql.cj.jdbc.Driver");
// 2. 建立連線
String url = "jdbc:mysql://localhost:3306/mydb?useSSL=false&serverTimezone=UTC";
Connection conn = DriverManager.getConnection(url, "user", "password");
// 3. 建立 Statement 並執行查詢
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("SELECT id, name, email FROM users");
// 4. 處理結果集
while (rs.next()) {
int id = rs.getInt("id");
String name = rs.getString("name");
String email = rs.getString("email");
System.out.printf("%d | %s | %s%n", id, name, email);
}
// 5. 關閉資源(建議使用 try-with-resources 自動關閉)
rs.close(); stmt.close(); conn.close();
jdbc:<subprotocol>:<subname>
jdbc:協定前綴subprotocol:子協定,如 mysql、postgresql、odbcsubname:資料源識別,可包含主機、埠號、資料庫名、屬性參數範例:jdbc:mysql://192.168.1.100:3306/erp_db?characterEncoding=UTF-8
使用 H2 內嵌資料庫示範(無需安裝外部 DB):
import java.sql.*;
public class StudentQueryDemo {
public static void main(String[] args) {
String url = "jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1";
String sql = "CREATE TABLE student (id INT PRIMARY KEY, name VARCHAR(50), age INT, chinese INT, math INT)";
String insert = "INSERT INTO student VALUES (1, '小明', 18, 92, 85), (2, '小華', 17, 78, 90)";
try (Connection conn = DriverManager.getConnection(url, "sa", "");
Statement stmt = conn.createStatement()) {
stmt.execute(sql);
stmt.execute(insert);
try (ResultSet rs = stmt.executeQuery("SELECT name, age, chinese, math FROM student")) {
System.out.println("姓名 年齡 國文 數學");
while (rs.next()) {
System.out.printf("%-4s %-3d %-3d %-3d%n",
rs.getString("name"), rs.getInt("age"),
rs.getInt("chinese"), rs.getInt("math"));
}
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
| 概念 | 進程 | 執行緒 |
|---|---|---|
| 定義 | 執行中的程式實例,擁有獨立記憶體空間 | 進程內的執行單元,共享進程資源 |
| 資源隔離 | 完全隔離,溝通需 IPC | 共享堆疊、堆積、檔案描述符 |
| 建立開銷 | 大(需配置獨立記憶體) | 小(輕量級進程) |
| 切換成本 | 高 | 低 |
run() 方法。缺點:Java 單一繼承限制,若類別已繼承其他父類(如 Applet),無法使用。run(),再傳給 Thread 建構子。推薦做法,支援多重實作、解耦任務與執行緒控制。六大狀態:NEW → RUNNABLE → BLOCKED / WAITING / TIMED_WAITING → TERMINATED。關鍵方法:
start():啟動執行緒(非直接呼叫 run())sleep(ms):讓出 CPU 進入 TIMED_WAITINGjoin():等待其他執行緒結束yield():禮讓同優先級執行緒interrupt():中斷阻塞狀態// 任務類別:實作 Runnable
class Racer implements Runnable {
private final String name;
private int position = 0;
private static final int FINISH_LINE = 100;
public Racer(String name) { this.name = name; }
@Override
public void run() {
while (position < FINISH_LINE) {
position++;
System.out.printf("%s 位置: %d%n", name, position);
try { Thread.sleep((int)(Math.random() * 50)); }
catch (InterruptedException e) { Thread.currentThread().interrupt(); break; }
}
System.out.println(name + " 衝線完成!");
}
}
// 主程式
public class RaceDemo {
public static void main(String[] args) {
Thread t1 = new Thread(new Racer("🏃 選手 A"));
Thread t2 = new Thread(new Racer("🏃 選手 B"));
Thread t3 = new Thread(new Racer("🏃 選手 C"));
t1.start(); t2.start(); t3.start();
}
}
實務開發中還需掌握:同步化、鎖機制、執行緒池、CompletableFuture 非同步程式設計、虛擬執行緒 等進階主題,建議後續深入研讀《Java Concurrency in Practice》。
傳統開發中,功能模組緊耦合、難以重用、升級維護成本高。元件技術將功能封裝為標準化、可獨立部署的單元(元件),像積木般組裝應用,實現「高內聚、低耦合」。
| 規範 | 發起者 | 平台相關性 | 特色 |
|---|---|---|---|
| CORBA | OMG 聯盟 | 跨平台 | 異構系統互通、IDL 介面定義語言、企業級分散式系統 |
| COM/DCOM/ActiveX | Microsoft | Windows 專屬 | 效能優異、Visual Basic 整合度高、曾統治桌面開發 |
| JavaBeans | Sun / Oracle | 跨平台 (Write Once, Run Anywhere) | 純 Java、支援序列化、Introspection 內省、屬性/事件/方法標準 |
一個合格的 Bean 必須遵循:
getXxx()/setXxx()(Boolean 型可用 isXxx())addXxxListener()/removeXxxListener(),支援觀察者模式BeanInfo 或命名慣例讓建構工具發現屬性/事件/方法
public class TemperatureBean implements java.io.Serializable {
private double celsius = 0.0;
private transient double fahrenheit; // 不序列化衍生屬性
// 屬性存取器
public double getCelsius() { return celsius; }
public void setCelsius(double c) {
this.celsius = c;
this.fahrenheit = c * 9/5 + 32;
firePropertyChange("celsius", null, c); // 通知監聽器
}
public double getFahrenheit() { return fahrenheit; }
// 事件支援
private final java.beans.PropertyChangeSupport pcs =
new java.beans.PropertyChangeSupport(this);
public void addPropertyChangeListener(java.beans.PropertyChangeListener l) {
pcs.addPropertyChangeListener(l);
}
public void removePropertyChangeListener(java.beans.PropertyChangeListener l) {
pcs.removePropertyChangeListener(l);
}
private void firePropertyChange(String prop, Object old, Object nw) {
pcs.firePropertyChange(prop, old, nw);
}
}
| 資源 | 網址 | 特色 |
|---|---|---|
| Baeldung | baeldung.com | 實戰導向、Spring 生態深度教學、每週更新 |
| InfoQ 中文站 | infoq.cn | 架構案例、新技術趨勢、大廠實踐分享 |
| 掘金 | juejin.cn | 中文技術社群、優質文章、小冊深度學習 |
| Java 專欄 | zhuanlan.zhihu.com/java | 知乎 Java 專題、專家觀點、面試熱點 |