首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 程式設計入門

JDBC 核心技術深度解析:從基礎 CRUD 到事務與批處理最佳實踐

     編輯:Java 程式設計入門

雖然現代開發多使用 ORM 框架,但 JDBC 作為 Java 資料訪問的基石,掌握其核心機制對理解上層框架原理、排查性能問題至關重要。本文系統梳理 JDBC 完整操作流程,涵蓋連接管理、CRUD、存儲過程、元數據、ResultSet 遊標操作、預處理/批處理優化、事務與 Savepoint 機制。

一、JDBC 基礎架構與連接建立

核心接口:DriverManager、Connection、Statement、PreparedStatement、CallableStatement、ResultSet、Savepoint。

1. 標準連接流程(以 Derby 嵌入式為例)

String driver = "org.apache.derby.jdbc.EmbeddedDriver";
String url = "jdbc:derby:EmbeddedDB;create=true";
Class.forName(driver);
Connection con = DriverManager.getConnection(url);
Statement st = con.createStatement();
st.execute("create table foo(ID INT, NAME VARCHAR(30))");
st.executeUpdate("insert into foo(ID,NAME) values(1,'Zhang San')");
ResultSet rs = st.executeQuery("select ID,NAME from foo");
while(rs.next()) System.out.println("ID=" + rs.getInt("ID") + "; NAME=" + rs.getString("NAME"));

2. 驅動自動加載(SPI 機制)

在 META-INF/services/java.sql.Driver 文件中寫入驅動全限定名(如 com.mysql.jdbc.Driver),JDK 6+ 會自動發現,無需 Class.forName()。注意仍需將驅動 JAR 放入 classpath。

二、CRUD 基礎操作(MySQL 示例)

String url = "jdbc:mysql://localhost/test";
Connection con = DriverManager.getConnection(url, "root", "123");
Statement st = con.createStatement();

// Insert
st.execute("insert into user(ID,NAME) values(1,'Zhang San')");

// Query
ResultSet rs = st.executeQuery("select ID,NAME from user");
while(rs.next()) System.out.println("ID:" + rs.getInt("ID") + "; NAME=" + rs.getString("NAME"));

// Update
st.executeUpdate("update user set NAME='TEST' where ID=2");

// Delete
st.execute("delete from user where ID=3");

三、存儲過程調用

1. 無參數過程

CallableStatement cst = con.prepareCall("call GetUser()");
ResultSet rs = cst.executeQuery();

2. IN 參數

// MySQL 過程:CREATE PROCEDURE GetUserByID(in id int) ...
CallableStatement cst = con.prepareCall("call GetUserByID(?)");
cst.setInt(1, id);
ResultSet rs = cst.executeQuery();

3. OUT 參數

使用 cst.registerOutParameter(index, Types.VARCHAR) 註冊,執行後 cst.getString(index) 獲取。

四、元數據編程

1. DatabaseMetaData:掃描數據庫結構

DatabaseMetaData dbmd = con.getMetaData();
System.out.println(dbmd.getDatabaseProductName() + " " + dbmd.getDatabaseProductVersion());
ResultSet rs = dbmd.getTables(null, null, null, null);
while(rs.next()) System.out.println(rs.getString("TABLE_NAME") + " " + rs.getString("TABLE_TYPE"));

2. ResultSetMetaData:分析結果集結構

ResultSetMetaData rsmd = rs.getMetaData();
for(int i=1; i<=rsmd.getColumnCount(); i++)
    System.out.println(rsmd.getColumnName(i) + " " + rsmd.getColumnTypeName(i));

五、可滾動/可更新 ResultSet 遊標操作

創建 Statement 時指定類型與併發性:

Statement st = con.createStatement(
    ResultSet.TYPE_SCROLL_SENSITIVE,
    ResultSet.CONCUR_UPDATABLE,
    ResultSet.CLOSE_CURSORS_AT_COMMIT);

關鍵方法:

  • rs.last() / rs.first() / rs.absolute(n):定位
  • rs.moveToInsertRow() / rs.updateXxx() / rs.insertRow():插入
  • rs.absolute(n) / rs.updateXxx() / rs.updateRow():更新
  • rs.absolute(n) / rs.deleteRow():刪除

示例流程:統計行數 → 插入 ID=4 → 更新最後一行 → 刪除最後一行,輸出驗證每步結果。

六、性能優化:預處理與批處理

1. PreparedStatement:SQL 預編譯緩存

PreparedStatement pst = con.prepareStatement("insert into user(id,name) values(?,?)");
pst.setInt(1, 5); pst.setString(2, "Lei Feng"); pst.executeUpdate();

2. Statement 批處理:減少網絡往返

Statement st = con.createStatement();
st.addBatch("insert into user(id,name) values(6,'Xiao Zhang')");
st.addBatch("insert into user(id,name) values(7,'Xiao Liu')");
st.executeBatch();

3. 組合:PreparedStatement + 批處理(最佳實踐)

PreparedStatement pst = con.prepareStatement("insert into user(id,name) values(?,?)");
pst.setInt(1, 9); pst.setString(2, "Xiao Zhang"); pst.addBatch();
pst.setInt(1, 10); pst.setString(2, "Xiao Liu"); pst.addBatch();
pst.executeBatch();

七、事務管理與 Savepoint

1. 基礎事務:關閉自動提交

con.setAutoCommit(false);
try {
    st.executeUpdate("insert into user(id,name) values(12,'Xiao Li')");
    con.commit();
} catch(Exception e) { con.rollback(); }
finally { con.setAutoCommit(true); }

連續執行兩次:首次成功,二次主鍵衝突拋異常並回滾。

2. Savepoint:部分回滾

Savepoint svpt = null;
con.setAutoCommit(false);
try {
    st.executeUpdate("insert into user(id,name) values(13,'Xiao Li')");
    st.executeUpdate("insert into user(id,name) values(14,'Xiao Wang')");
    svpt = con.setSavepoint("roll back to here");
    st.executeUpdate("insert into user(id,name) values(15,'Xiao Zhao')");
    st.executeUpdate("insert into user(id,name) values(13,'Xiao Li')"); // 主鍵衝突
    con.commit();
} catch(Exception e) { con.rollback(svpt); }
finally { con.setAutoCommit(true); }

結果:ID 13、14 保留;ID 15 回滾;異常拋出後事務部分提交。

八、最佳實踐清單

  1. 生產環境務必使用連接池(HikariCP/Druid),避免頻繁創建銷毀連接。
  2. 所有 SQL 參數化,杜絕字符串拼接,防 SQL 注入並利用預編譯緩存。
  3. 批量寫入優先 PreparedStatement.addBatch(),適當調大 rewriteBatchedStatements=true(MySQL)。
  4. 事務邊界清晰:業務方法層面控制,避免長事務持有鎖。
  5. 資源關閉使用 try-with-resources(JDK 7+)保證釋放。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved