Java JDBC核心概念与实战详解
用于实现 Java 程序与各类关系型数据库(MySQL、Oracle、PostgreSQL 等)的交互。JDBC(Java Database Connectivity)是 Java 提供的一套。以 MySQL 为例,实现 “查询用户 + 新增用户” 的完整流程,包含。避免 SQL 注入)。
·
一、JDBC 核心概念详解
JDBC(Java Database Connectivity)是 Java 提供的一套标准接口,用于实现 Java 程序与各类关系型数据库(MySQL、Oracle、PostgreSQL 等)的交互。简单来说:
- JDBC 本身不是具体实现,而是定义了 “怎么操作数据库” 的规范;
- 各大数据库厂商(如 MySQL)会提供符合 JDBC 规范的驱动包(如 mysql-connector-java),这才是真正实现数据库连接、SQL 执行的底层代码;
- 开发者只需调用 JDBC 接口,无需关心不同数据库的底层差异(这也是 “面向接口编程” 的典型应用)。
1. JDBC 核心组件(5 个关键接口 / 类)
| 组件 | 作用 |
|---|---|
DriverManager |
管理数据库驱动,创建数据库连接(Connection) |
Connection |
代表 Java 程序与数据库的物理连接,是所有数据库操作的基础 |
Statement/PreparedStatement |
执行 SQL 语句的对象(PreparedStatement 更安全,推荐使用) |
ResultSet |
存储 SQL 查询(SELECT)的结果集,可遍历获取数据 |
SQLException |
处理 JDBC 操作中所有数据库相关的异常 |
2. JDBC 核心优势
- 跨数据库兼容:一套代码适配不同数据库(只需更换驱动和连接串);
- 底层可控:相比 ORM 框架(如 MyBatis),更贴近数据库底层,适合简单场景或性能优化;
- 标准统一:Java 官方定义,无需依赖第三方框架。
二、JDBC 完整执行流程(8 步)
- 加载 / 注册数据库驱动(MySQL 8.0+ 可省略,自动加载);
- 通过
DriverManager获取Connection连接; - 创建
PreparedStatement(推荐)/Statement对象,封装 SQL 语句; - 执行 SQL 语句(
executeQuery查 /executeUpdate增删改); - 处理执行结果(遍历
ResultSet或获取受影响行数); - 关闭
ResultSet(查询时); - 关闭
PreparedStatement/Statement; - 关闭
Connection(必须关闭,否则占用数据库连接资源)。
三、完整可运行代码示例
以 MySQL 为例,实现 “查询用户 + 新增用户” 的完整流程,包含异常处理、资源关闭、参数防注入(用 PreparedStatement 避免 SQL 注入)。
前置准备
- 引入 MySQL 驱动依赖(Maven):
<!-- pom.xml 中添加 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.33</version> <!-- 适配 MySQL 8.0+,5.x 用 5.1.49 -->
<scope>runtime</scope>
</dependency>
- 数据库准备(创建测试表):
CREATE DATABASE IF NOT EXISTS jdbc_demo;
USE jdbc_demo;
CREATE TABLE IF NOT EXISTS user (
id INT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(50) NOT NULL,
age INT
);
完整 Java 代码
import java.sql.*;
/**
* JDBC 完整执行流程示例:查询+新增用户
*/
public class JdbcCompleteDemo {
// 数据库连接信息(根据自己的环境修改)
private static final String DB_URL = "jdbc:mysql://localhost:3306/jdbc_demo?useSSL=false&serverTimezone=UTC&characterEncoding=utf8";
private static final String DB_USER = "root"; // 你的数据库用户名
private static final String DB_PASSWORD = "123456"; // 你的数据库密码
public static void main(String[] args) {
// 1. 新增用户
insertUser("张三", 25);
insertUser("李四", 30);
// 2. 查询所有用户
queryAllUsers();
}
/**
* 新增用户(增删改用 executeUpdate)
* @param username 用户名
* @param age 年龄
*/
public static void insertUser(String username, int age) {
Connection conn = null;
PreparedStatement pstmt = null;
try {
// 步骤1:获取数据库连接(MySQL 8.0+ 无需手动加载驱动)
conn = DriverManager.getConnection(DB_URL, DB_USER, DB_PASSWORD);
// 步骤2:创建 PreparedStatement(? 是参数占位符,防 SQL 注入)
String sql = "INSERT INTO user (username, age) VALUES (?, ?)";
pstmt = conn.prepareStatement(sql);
// 给占位符赋值(索引从 1 开始)
pstmt.setString(1, username);
pstmt.setInt(2, age);
// 步骤3:执行 SQL(executeUpdate 返回受影响行数)
int affectedRows = pstmt.executeUpdate();
System.out.println("新增用户成功,受影响行数:" + affectedRows);
} catch (SQLException e) {
// 异常处理(实际开发中可封装为自定义异常)
e.printStackTrace();
} finally {
// 步骤4:关闭资源(逆序关闭,先关 Statement,再关 Connection)
closeResource(conn, pstmt, null);
}
}
/**
* 查询所有用户(查询用 executeQuery,返回 ResultSet)
*/
public static void queryAllUsers() {
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
// 步骤1:获取连接
conn = DriverManager.getConnection(DB_URL, DB_USER, DB_PASSWORD);
// 步骤2:创建 PreparedStatement
String sql = "SELECT id, username, age FROM user";
pstmt = conn.prepareStatement(sql);
// 步骤3:执行查询,获取结果集
rs = pstmt.executeQuery();
// 步骤4:遍历结果集
System.out.println("\n===== 用户列表 =====");
while (rs.next()) { // rs.next() 移动到下一行,无数据时返回 false
int id = rs.getInt("id"); // 通过列名获取值
String username = rs.getString("username");
int age = rs.getInt("age");
System.out.printf("ID:%d,用户名:%s,年龄:%d%n", id, username, age);
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
// 步骤5:关闭资源(包含 ResultSet)
closeResource(conn, pstmt, rs);
}
}
/**
* 统一关闭 JDBC 资源的工具方法(避免重复代码)
* @param conn 连接对象
* @param stmt 执行 SQL 的对象
* @param rs 结果集(查询时才用)
*/
private static void closeResource(Connection conn, Statement stmt, ResultSet rs) {
try {
if (rs != null) {
rs.close(); // 关闭结果集
}
if (stmt != null) {
stmt.close(); // 关闭 Statement
}
if (conn != null) {
conn.close(); // 关闭连接
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
代码关键说明
- PreparedStatement 为什么推荐用?
- 防 SQL 注入:参数通过占位符
?赋值,而非拼接字符串(比如username='张三' OR 1=1这类注入语句会失效); - 性能优化:可预编译 SQL,重复执行时无需重新解析。
- 防 SQL 注入:参数通过占位符
- 资源关闭的重要性:
- 数据库连接是稀缺资源,必须在
finally中关闭(无论是否异常); - 关闭顺序:
ResultSet→Statement→Connection(创建顺序的逆序)。
- 数据库连接是稀缺资源,必须在
- MySQL 8.0+ 注意点:
- 驱动类路径从
com.mysql.jdbc.Driver改为com.mysql.cj.jdbc.Driver; - 连接串必须指定
serverTimezone(如 UTC、Asia/Shanghai),否则报错。
- 驱动类路径从
更多推荐
所有评论(0)