JDBC(Java Database Connectivity)是 Java 訪問關係型數據庫的統一 API。本文以 SQL Server 2012+ 為例,涵蓋驅動下載、Maven/Gradle 依賴、連接參數、CRUD 完整代碼、預編譯防注入、事務控制與連接池最佳實踐。
<dependency>
<groupId>com.microsoft.sqlserver</groupId>
<artifactId>mssql-jdbc</artifactId>
<version>12.4.2.jre11</version> <!-- 根據 JDK 版本選擇 jre8/jre11/jre17 -->
</dependency>
CREATE DATABASE java_conn_test;public class JdbcUtil {
private static final String URL = "jdbc:sqlserver://localhost:1433;DatabaseName=java_conn_test;encrypt=true;trustServerCertificate=true";
private static final String USER = "sa";
private static final String PASS = "123456";
static {
try { Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver"); }
catch (ClassNotFoundException e) { throw new ExceptionInInitializerError(e); }
}
public static Connection getConnection() throws SQLException {
return DriverManager.getConnection(URL, USER, PASS);
}
public static void close(Connection c, Statement s, ResultSet r) {
try { if (r != null) r.close(); } catch (SQLException ignore) {}
try { if (s != null) s.close(); } catch (SQLException ignore) {}
try { if (c != null) c.close(); } catch (SQLException ignore) {}
}
}
關鍵參數:encrypt=true;trustServerCertificate=true 解決 JDK 11+ 默認要求 SSL 加密導致的連接失敗。
public List<User> queryAll() {
String sql = "SELECT UserId, UserName, UserPwd FROM tb_User";
try (Connection c = JdbcUtil.getConnection();
PreparedStatement ps = c.prepareStatement(sql);
ResultSet rs = ps.executeQuery()) {
List<User> list = new ArrayList<>();
while (rs.next()) {
list.add(new User(rs.getString("UserId"), rs.getString("UserName"), rs.getString("UserPwd")));
}
return list;
} catch (SQLException e) { throw new RuntimeException(e); }
}
public int insert(User u) {
String sql = "INSERT INTO tb_User (UserId, UserName, UserPwd) VALUES (NEWID(), ?, ?)";
try (Connection c = JdbcUtil.getConnection();
PreparedStatement ps = c.prepareStatement(sql)) {
ps.setString(1, u.getUserName());
ps.setString(2, u.getUserPwd());
return ps.executeUpdate();
} catch (SQLException e) { throw new RuntimeException(e); }
}
public int updatePwd(String userId, String newPwd) {
String sql = "UPDATE tb_User SET UserPwd = ? WHERE UserId = ?";
try (Connection c = JdbcUtil.getConnection();
PreparedStatement ps = c.prepareStatement(sql)) {
ps.setString(1, newPwd);
ps.setString(2, userId);
return ps.executeUpdate();
} catch (SQLException e) { throw new RuntimeException(e); }
}
public int delete(String userId) {
String sql = "DELETE FROM tb_User WHERE UserId = ?";
try (Connection c = JdbcUtil.getConnection();
PreparedStatement ps = c.prepareStatement(sql)) {
ps.setString(1, userId);
return ps.executeUpdate();
} catch (SQLException e) { throw new RuntimeException(e); }
}
public void transfer(String fromId, String toId, double amount) {
Connection c = null;
try {
c = JdbcUtil.getConnection();
c.setAutoCommit(false); // 開啟事務
// 扣款
try (PreparedStatement ps = c.prepareStatement("UPDATE tb_Account SET balance = balance - ? WHERE user_id = ?")) {
ps.setDouble(1, amount);
ps.setString(2, fromId);
ps.executeUpdate();
}
// 入賬
try (PreparedStatement ps = c.prepareStatement("UPDATE tb_Account SET balance = balance + ? WHERE user_id = ?")) {
ps.setDouble(1, amount);
ps.setString(2, toId);
ps.executeUpdate();
}
c.commit(); // 提交
} catch (SQLException e) {
try { if (c != null) c.rollback(); } catch (SQLException ignore) {}
throw new RuntimeException("轉賬失敗", e);
} finally {
try { if (c != null) c.setAutoCommit(true); } catch (SQLException ignore) {}
JdbcUtil.close(c, null, null);
}
}
<dependency>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
<version>5.0.1</version>
</dependency>
public class DataSourceUtil {
private static final HikariDataSource ds = new HikariDataSource();
static {
ds.setJdbcUrl("jdbc:sqlserver://localhost:1433;DatabaseName=java_conn_test;encrypt=true;trustServerCertificate=true");
ds.setUsername("sa");
ds.setPassword("123456");
ds.setMaximumPoolSize(20);
ds.setMinimumIdle(5);
ds.setIdleTimeout(300_000);
ds.setConnectionTimeout(30_000);
ds.setPoolName("SQLServer-Pool");
}
public static DataSource getDataSource() { return ds; }
}
後續直接 DataSourceUtil.getDataSource().getConnection() 獲取連接,無需手動關閉(歸還池中)。
| 現象 | 原因 | 解決 |
|---|---|---|
| The driver could not establish a secure connection | JDK 11+ 默認 SSL,驅動版本過低或未配置信任憑證 | 升級驅動 12.2+,URL 加 trustServerCertificate=true |
| Login failed for user 'sa' | 密碼錯誤/未啟用混合驗證/sa 鎖定 | SSMS 重置密碼、啟用 SQL 驗證、解鎖登錄 |
| ResultSet 獲取不到數據 | 游標默認 TYPE_FORWARD_ONLY,需 rs.next() 推進 | while(rs.next()) 循環讀取 |
| PreparedStatement 防注入失效 | 拼接 SQL 字符串而非用 ? 佔位符 | 全部參數化,動態 IN 列表用 String.join 生成 ? 序列 |
掌握 JDBC 核心流程:加載驅動 → 獲取連接 → 預編譯 SQL → 綁參數 → 執行 → 處理結果 → 釋放資源。生產環境務必上連接池、統一異常處理、開啟慢 SQL 監控。下一步可學習 MyBatis/JPA 等 ORM 框架提升開發效率。