JDBC 四大核心对象
- DriverManager:驱动管理,加载驱动、获取连接。
- Connection:数据库连接会话,事务管理、创建 Statement。
- Statement / PreparedStatement:SQL 执行载体。
- ResultSet:结果集游标,遍历查询结果。
1. 驱动加载:推荐方式
// 不推荐:DriverManager.registerDriver(new com.mysql.jdbc.Driver());
// 问题:驱动注册两次、强依赖具体驱动类
// 推荐:反射加载,解耦驱动实现
Class.forName("com.mysql.jdbc.Driver"); // JDBC 4.0+ 甚至可省略(SPI 自动加载)
2. 获取连接
// 方式一:URL + 用户名/密码
String url = "jdbc:mysql://localhost:3306/day06?useSSL=false&serverTimezone=UTC";
Connection conn = DriverManager.getConnection(url, "root", "root");
// 方式二:Properties 对象(适配多数据源配置文件)
Properties props = new Properties();
props.setProperty("user", "root");
props.setProperty("password", "root");
Connection conn = DriverManager.getConnection(url, props);
// 常见数据库 URL 格式
// MySQL: jdbc:mysql://host:port/dbname
// Oracle: jdbc:oracle:thin:@host:port:sid
3. Statement vs PreparedStatement
| 特性 | Statement | PreparedStatement |
| SQL 注入 | 风险高(拼接字符串) | **免疫**(预编译+参数绑定) |
| 性能 | 每次编译 | 预编译一次,多次执行高效 |
| 参数设置 | 不支持 | setXxx(index, val) 类型安全 |
| 批处理 | 支持 | 支持 addBatch()/executeBatch() |
结论:生产环境 99% 场景使用 PreparedStatement。
PreparedStatement 使用模板
// 查询
String sql = "SELECT * FROM users WHERE username=? AND pwd=?";
PreparedStatement ps = conn.prepareStatement(sql);
ps.setString(1, "tom");
ps.setString(2, "123");
ResultSet rs = ps.executeQuery();
// 更新/删除/插入
String sql = "DELETE FROM users WHERE id=?";
PreparedStatement ps = conn.prepareStatement(sql);
ps.setInt(1, 5);
int rows = ps.executeUpdate(); // 返回影响行数
4. ResultSet 结果集遍历
while (rs.next()) { // 游标下移,返回是否有数据
User u = new User();
u.setId(rs.getInt("id")); // 推荐用列名,可读性强
u.setName(rs.getString("name"));
u.setBirthday(rs.getDate("birthday"));
list.add(u);
}
5. 资源关闭:标准 finally 模式(JDK 7+ try-with-resources 更优)
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
conn = DriverManager.getConnection(url, user, pwd);
ps = conn.prepareStatement(sql);
// ... 设置参数、执行 ...
rs = ps.executeQuery();
// ... 处理结果 ...
} catch (SQLException e) {
e.printStackTrace();
} finally {
// 逆序关闭,单独 try-catch 保证都能关闭
if (rs != null) try { rs.close(); } catch (SQLException e) { e.printStackTrace(); }
if (ps != null) try { ps.close(); } catch (SQLException e) { e.printStackTrace(); }
if (conn != null) try { conn.close(); } catch (SQLException e) { e.printStackTrace(); }
}
完整 CRUD 示例
public class JdbcDemo {
static final String URL = "jdbc:mysql:///day06?useSSL=false";
static final String USER = "root";
static final String PWD = "abc";
public static void main(String[] args) {
String sql = "SELECT * FROM users WHERE name=? AND pwd=?";
try (Connection conn = DriverManager.getConnection(URL, USER, PWD);
PreparedStatement ps = conn.prepareStatement(sql)) {
ps.setString(1, "tom");
ps.setString(2, "123");
try (ResultSet rs = ps.executeQuery()) {
while (rs.next()) {
System.out.println(rs.getInt("id") + " " + rs.getString("name"));
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
总结
- 驱动加载用
Class.forName 或依赖 SPI。
- **永远使用 PreparedStatement** 防注入、提性能。
- 资源关闭用
try-with-resources(JDK 7+)保证不泄漏。
- 事务控制:
conn.setAutoCommit(false) → 执行多条 SQL → conn.commit()/rollback()。
- 上一篇文章: 架构师该不该写代码? —— 兼谈技术领导力的“后勤保障”模式
- 下一篇文章: 博客園文章編輯測試:發布後能否修改內容?
Copyright ©
程式碼之家 All Rights Reserved