一、JDBC 概述
1.1 什么是 JDBC?
JDBC(Java Database Connectivity,Java 数据库连接)是 Java 语言操作关系型数据库的一套标准接口。
它定义了一系列规范,由各数据库厂商(如 MySQL、Oracle、SQL Server)提供对应的驱动实现。
开发者只需面向 JDBC 接口编程,无需关心底层数据库的具体实现,实现 “一次编写,到处运行”。
1.2 JDBC 的本质
官方定义的一套操作所有关系型数据库的规范接口。
各数据库厂商提供的驱动包,是这些接口的实现类。
开发者使用 JDBC 接口编程,实际执行的代码是驱动包中的实现类。
1.3 JDBC 的好处
跨数据库兼容:更换数据库时,只需更换驱动包和连接 URL,业务代码无需修改。
标准化 API:所有数据库操作都遵循统一的接口规范,学习成本低。
稳定性高:作为 Java 官方标准,长期维护,兼容性有保障。
二、JDBC 快速入门
2.1 开发步骤
导入驱动包:将 MySQL 驱动
mysql-connector-java-x.x.x.jar添加到项目依赖中。注册驱动:加载数据库驱动类。
获取连接:建立 Java 程序与数据库的连接。
编写 SQL 语句:定义要执行的数据库操作(增删改查)。
获取执行对象:创建 SQL 语句的执行对象。
执行 SQL:执行 SQL 语句并获取结果。
处理结果:对查询结果或影响行数进行处理。
释放资源:关闭连接、执行对象等资源。
2.2 入门示例(更新操作)
import java.sql.Connection; import java.sql.DriverManager; import java.sql.Statement; public class JdbcQuickStart { public static void main(String[] args) throws Exception { // 1. 注册驱动(MySQL 5.0+ 可省略) Class.forName("com.mysql.cj.jdbc.Driver"); // 2. 获取数据库连接 String url = "jdbc:mysql://localhost:3306/testdb?useSSL=false&serverTimezone=UTC"; String username = "root"; String password = "root"; Connection conn = DriverManager.getConnection(url, username, password); // 3. 获取执行对象 Statement stmt = conn.createStatement(); // 4. 编写并执行 SQL(更新账户余额) String sql = "UPDATE account SET money = money - 200 WHERE id = 1"; int count = stmt.executeUpdate(sql); // 5. 处理结果 System.out.println("影响行数:" + count); // 6. 释放资源(逆序关闭) stmt.close(); conn.close(); } }三、JDBC 核心 API 详解
3.1DriverManager(驱动管理类)
注册驱动:
Class.forName("com.mysql.cj.jdbc.Driver");MySQL 5.0+ 驱动包中,
Driver类会自动注册,无需手动调用。
获取连接:
DriverManager.getConnection(url, username, password);
URL 格式:
jdbc:mysql://主机地址:端口号/数据库名?参数
示例:
jdbc:mysql://localhost:3306/testdb?useSSL=false&serverTimezone=UTC常用参数:
useSSL=false(关闭 SSL 验证)、serverTimezone=UTC(设置时区)
3.2Connection(数据库连接对象)
获取 SQL 执行对象:
createStatement():创建普通Statement对象(存在 SQL 注入风险)。prepareStatement(String sql):创建预编译PreparedStatement对象(推荐,防注入)。
事务管理:
setAutoCommit(false):关闭自动提交,开启事务。commit():提交事务。rollback():回滚事务。
事务示例
try { conn.setAutoCommit(false); // 开启事务 // 执行转账操作 stmt.executeUpdate("UPDATE account SET money = money - 200 WHERE id = 1"); stmt.executeUpdate("UPDATE account SET money = money + 200 WHERE id = 2"); conn.commit(); // 提交事务 } catch (Exception e) { conn.rollback(); // 异常时回滚事务 e.printStackTrace(); } finally { // 释放资源 }3.3Statement(SQL 执行对象)
executeUpdate(String sql):执行 DML(增删改)语句,返回受影响行数。executeQuery(String sql):执行 DQL(查询)语句,返回ResultSet结果集对象。
3.4ResultSet(结果集对象)
封装查询语句的执行结果,提供遍历和获取数据的方法。
常用方法:
next():将游标向下移动一行,判断是否有数据。getInt("列名")/getInt(列索引):获取整数类型数据。getString("列名")/getString(列索引):获取字符串类型数据。getDouble("列名")/getDouble(列索引):获取小数类型数据。
查询示例
String sql = "SELECT id, name, money FROM account"; ResultSet rs = stmt.executeQuery(sql); // 遍历结果集 while (rs.next()) { int id = rs.getInt("id"); String name = rs.getString("name"); double money = rs.getDouble("money"); System.out.println("ID: " + id + ", 姓名: " + name + ", 余额: " + money); } rs.close(); // 释放结果集3.5PreparedStatement(预编译执行对象)
解决
Statement的 SQL 注入问题,推荐使用。SQL 注入:通过拼接用户输入恶意修改 SQL 语句,例如
' or '1' = '1。使用步骤:
编写带
?占位符的 SQL 语句。创建
PreparedStatement对象,传入 SQL 语句。使用
setXxx(参数索引, 值)方法为占位符赋值(索引从 1 开始)。执行 SQL 语句。
防注入登录示例
// 1. 带占位符的 SQL String sql = "SELECT * FROM user WHERE username = ? AND password = ?"; // 2. 获取预编译对象 PreparedStatement pstmt = conn.prepareStatement(sql); // 3. 为占位符赋值 pstmt.setString(1, username); pstmt.setString(2, password); // 4. 执行查询 ResultSet rs = pstmt.executeQuery(); // 5. 判断是否存在用户 if (rs.next()) { System.out.println("登录成功!"); } else { System.out.println("用户名或密码错误!"); }四、综合实践:JDBC 工具类与数据封装
4.1 工具类JDBCUtils
封装 JDBC 连接和释放资源的重复代码,提高开发效率。
import java.sql.*; public class JDBCUtils { // 数据库配置(可从配置文件读取) private static final String URL = "jdbc:mysql://localhost:3306/testdb?useSSL=false&serverTimezone=UTC"; private static final String USERNAME = "root"; private static final String PASSWORD = "root"; // 注册驱动 static { try { Class.forName("com.mysql.cj.jdbc.Driver"); } catch (ClassNotFoundException e) { throw new RuntimeException("驱动加载失败", e); } } // 获取连接 public static Connection getConnection() throws SQLException { return DriverManager.getConnection(URL, USERNAME, PASSWORD); } // 释放资源 public static void close(Connection conn, Statement stmt, ResultSet rs) { try { if (rs != null) rs.close(); if (stmt != null) stmt.close(); if (conn != null) conn.close(); } catch (SQLException e) { e.printStackTrace(); } } // 简化版释放(无查询结果) public static void close(Connection conn, Statement stmt) { close(conn, stmt, null); } }4.2 数据封装示例(查询账户列表)
import java.util.ArrayList; import java.util.List; public class Account { private int id; private String name; private double money; // 构造方法、getter/setter、toString public Account() {} public Account(int id, String name, double money) { this.id = id; this.name = name; this.money = money; } // getter/setter 省略 @Override public String toString() { return "Account{id=" + id + ", name='" + name + "', money=" + money + "}"; } } // 查询方法 public List<Account> findAllAccounts() { List<Account> list = new ArrayList<>(); Connection conn = null; PreparedStatement pstmt = null; ResultSet rs = null; try { conn = JDBCUtils.getConnection(); String sql = "SELECT id, name, money FROM account"; pstmt = conn.prepareStatement(sql); rs = pstmt.executeQuery(); while (rs.next()) { int id = rs.getInt("id"); String name = rs.getString("name"); double money = rs.getDouble("money"); list.add(new Account(id, name, money)); } } catch (SQLException e) { e.printStackTrace(); } finally { JDBCUtils.close(conn, pstmt, rs); } return list; }五、核心记忆要点
JDBC 流程:注册驱动 → 获取连接 → 创建执行对象 → 执行 SQL → 处理结果 → 释放资源。
连接 URL:
jdbc:mysql://主机:端口/数据库?参数,必须配置时区和 SSL 参数。执行对象选择:优先使用
PreparedStatement,避免 SQL 注入并提高性能。事务管理:通过
Connection的setAutoCommit(false)、commit()、rollback()实现事务控制。资源释放:必须逆序关闭
ResultSet→Statement→Connection,建议使用try-finally或工具类统一处理。