Oracle 作為企業級數據庫的佼佼者,與 Java 的整合是後端開發的必修課。本文提供從驅動配置、表結構設計、連接參數優化到完整 CRUD 操作的端到端實戰指南,代碼即拿即用,適合快速落地項目。
<!-- Maven -->
<dependency>
<groupId>com.oracle.database.jdbc</groupId>
<artifactId>ojdbc8</artifactId> <!-- JDK 8+ 使用 ojdbc8,JDK 11+ 推薦 ojdbc11 -->
<version>21.9.0.0</version>
</dependency>
mvn install:install-file -Dfile=ojdbc8.jar -DgroupId=com.oracle -DartifactId=ojdbc8 -Dversion=21.9.0.0 -Dpackaging=jar
注意:Oracle JDBC 驅動因版權原因不在 Maven Central,需從 Oracle 官網下載或配置私服。
-- 創建學生表
CREATE TABLE student (
id NUMBER(11) NOT NULL PRIMARY KEY,
stu_name VARCHAR2(16) NOT NULL,
gender NUMBER(11) DEFAULT NULL, -- 1:男 2:女
age NUMBER(11) DEFAULT NULL,
address VARCHAR2(128) DEFAULT NULL
);
-- 插入測試數據
INSERT INTO student VALUES (1, '王小軍', 1, 17, '北京市和平裡七區30號樓7門102');
COMMIT;
public class OracleConfig {
// 精簡版 Oracle (XE) 默認配置
public static final String DRIVER = "oracle.jdbc.OracleDriver";
public static final String URL = "jdbc:oracle:thin:@192.168.0.100:1521:XE"; // 替換為實際 IP/SID
public static final String USERNAME = "orcl";
public static final String PASSWORD = "orcl";
// 生產環境建議使用服務名
// jdbc:oracle:thin:@//host:port/service_name
// 連接池優化參數 (HikariCP 示例)
// maximumPoolSize=20
// minimumIdle=5
// connectionTimeout=30000
// idleTimeout=600000
// maxLifetime=1800000
}
public class StudentDao {
private Connection connection;
private PreparedStatement pstm;
private ResultSet rs;
// 獲取連接 (建議配合連接池使用)
private Connection getConnection() throws SQLException {
try {
Class.forName(OracleConfig.DRIVER);
connection = DriverManager.getConnection(
OracleConfig.URL, OracleConfig.USERNAME, OracleConfig.PASSWORD);
System.out.println("✅ Oracle 數據庫連接成功");
} catch (ClassNotFoundException e) {
throw new RuntimeException("❌ 驅動類未找到", e);
} catch (SQLException e) {
throw new RuntimeException("❌ 連接失敗", e);
}
return connection;
}
// 釋放資源 (反向關閉)
private void releaseResource() {
try { if (rs != null) rs.close(); } catch (SQLException e) { e.printStackTrace(); }
try { if (pstm != null) pstm.close(); } catch (SQLException e) { e.printStackTrace(); }
try { if (connection != null) connection.close(); } catch (SQLException e) { e.printStackTrace(); }
}
// ============ CRUD 操作 ============
// 新增學生 (自動生成 ID)
public void addStudent(String name, int gender, int age, String address) {
String countSql = "SELECT COUNT(*) FROM student";
String insertSql = "INSERT INTO student (id, stu_name, gender, age, address) VALUES (?, ?, ?, ?, ?)";
try {
getConnection();
// 獲取當前最大 ID + 1 (生產環境建議使用 Sequence)
pstm = connection.prepareStatement(countSql);
rs = pstm.executeQuery();
int nextId = 1;
if (rs.next()) nextId = rs.getInt(1) + 1;
// 執行插入
pstm = connection.prepareStatement(insertSql);
pstm.setInt(1, nextId);
pstm.setString(2, name);
pstm.setInt(3, gender);
pstm.setInt(4, age);
pstm.setString(5, address);
int rows = pstm.executeUpdate();
System.out.println(rows > 0 ? "✅ 新增成功,ID: " + nextId : "❌ 新增失敗");
} catch (SQLException e) {
e.printStackTrace();
} finally {
releaseResource();
}
}
// 按姓名刪除
public void deleteStudentByName(String name) {
String sql = "DELETE FROM student WHERE stu_name = ?";
try {
getConnection();
pstm = connection.prepareStatement(sql);
pstm.setString(1, name);
int rows = pstm.executeUpdate();
System.out.println(rows > 0 ? "✅ 刪除成功,影響行數: " + rows : "⚠️ 未找到匹配記錄");
} catch (SQLException e) {
e.printStackTrace();
} finally {
releaseResource();
}
}
// 更新學生信息
public void updateStudent(String name, int gender, int age, String address) {
String idSql = "SELECT id FROM student WHERE stu_name = ?";
String updateSql = "UPDATE student SET stu_name=?, gender=?, age=?, address=? WHERE id=?";
try {
getConnection();
// 先查 ID
pstm = connection.prepareStatement(idSql);
pstm.setString(1, name);
rs = pstm.executeQuery();
int id = 0;
if (rs.next()) id = rs.getInt(1);
else { System.out.println("⚠️ 學生不存在"); return; }
// 執行更新
pstm = connection.prepareStatement(updateSql);
pstm.setString(1, name);
pstm.setInt(2, gender);
pstm.setInt(3, age);
pstm.setString(4, address);
pstm.setInt(5, id);
int rows = pstm.executeUpdate();
System.out.println(rows > 0 ? "✅ 更新成功" : "❌ 更新失敗");
} catch (SQLException e) {
e.printStackTrace();
} finally {
releaseResource();
}
}
// 查詢所有學生
public void queryAllStudents() {
String sql = "SELECT * FROM student";
try {
getConnection();
pstm = connection.prepareStatement(sql);
rs = pstm.executeQuery();
System.out.println("ID\t姓名\t性別\t年齡\t地址");
System.out.println("------------------------------------------------");
while (rs.next()) {
System.out.printf("%d\t%s\t%d\t%d\t%s%n",
rs.getInt("id"),
rs.getString("stu_name"),
rs.getInt("gender"),
rs.getInt("age"),
rs.getString("address"));
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
releaseResource();
}
}
// 使用 ResultSetMetaData 獲取列信息
public void queryWithMetaData() {
String sql = "SELECT * FROM student";
try {
getConnection();
pstm = connection.prepareStatement(sql);
rs = pstm.executeQuery();
ResultSetMetaData meta = rs.getMetaData();
int columnCount = meta.getColumnCount();
// 打印列名
for (int i = 1; i <= columnCount; i++) {
System.out.printf("%-15s", meta.getColumnLabel(i));
}
System.out.println();
// 打印數據
while (rs.next()) {
for (int i = 1; i <= columnCount; i++) {
System.out.printf("%-15s", rs.getObject(i));
}
System.out.println();
}
System.out.println("列數: " + columnCount);
} catch (SQLException e) {
e.printStackTrace();
} finally {
releaseResource();
}
}
}
public class OracleTest {
public static void main(String[] args) {
StudentDao dao = new StudentDao();
System.out.println("=== 1. 查詢初始數據 ===");
dao.queryAllStudents();
System.out.println("\n=== 2. 新增學生 ===");
dao.addStudent("孫中山", 1, 25, "北京市海澱區紅旗路111號");
System.out.println("\n=== 3. 查詢新增後 ===");
dao.queryAllStudents();
System.out.println("\n=== 4. 更新學生 ===");
dao.updateStudent("孫中山", 1, 30, "北京市東城區岳山路11號");
System.out.println("\n=== 5. 查詢更新後 ===");
dao.queryAllStudents();
System.out.println("\n=== 6. 刪除學生 ===");
dao.deleteStudentByName("孫中山");
System.out.println("\n=== 7. 最終數據 ===");
dao.queryAllStudents();
System.out.println("\n=== 8. 元數據查詢 ===");
dao.queryWithMetaData();
}
}
| 錯誤現象 | 可能原因 | 解決方案 |
|---|---|---|
| ORA-12505: TNS:listener does not currently know of SID | SID/服務名錯誤 | 確認 tnsnames.ora、使用服務名而非 SID |
| ORA-28040: No matching authentication protocol | JDK/驅動版本與數據庫不兼容 | 升級 ojdbc8/11,或數據庫設置 SQLNET.ALLOWED_LOGON_VERSION_SERVER=8 |
| 中文亂碼 (???) | 字符集不匹配 | 確認 NLS_LANG 環境變量、數據庫字符集 AL32UTF8、JVM -Dfile.encoding=UTF-8 |
| 連接泄漏導致 ORA-00020 | 未正確關閉連接/連接池配置不當 | 使用 try-with-resources、監控連接池指標、設置 maxLifetime |
掌握 Java 操作 Oracle 的核心套路:驅動加載 → 連接獲取 → PreparedStatement 預編譯 → 參數綁定 → 執行 → 結果集處理 → 資源釋放。將此模板內化為肌肉記憶,配合連接池與事務管理,即可應對絕大多數企業級開發場景。