十六、java JDBC知识点

0 阅读9分钟

Java JDBC 超详细全知识点整理

本文是Java JDBC 最全、最细、无死角的知识点总结,从基础概念、核心API、执行流程,到高级特性、性能优化、分布式事务、常见问题全覆盖,适合零基础入门、面试复习、项目实战。

一、JDBC 基础概念

1. 什么是 JDBC

JDBC(Java Database Connectivity)是Java 官方定义的一套用于执行 SQL 语句的 API(接口规范),它让 Java 程序可以统一方式连接、操作各种关系型数据库(MySQL、Oracle、SQLServer、PostgreSQL 等)。

  • 本质:接口 + 实现类
  • 作用:屏蔽不同数据库的底层差异,实现「一套代码,多数据库运行」

2. JDBC 核心架构

  1. JDBC API:Java 官方提供,开发者直接使用(java.sqljavax.sql 包)
  2. JDBC Driver:数据库厂商实现的驱动类(实现 JDBC 接口),负责和数据库通信
  3. Java 应用程序:调用 JDBC API,驱动自动完成底层通信

3. JDBC 驱动类型(4 种)

类型名称特点适用场景
1JDBC-ODBC 桥驱动性能差、依赖本地 ODBC已废弃
2本地 API 驱动调用数据库本地 C/C++ 库兼容性差,极少用
3网络协议驱动中间件转发请求企业级专用
4纯 Java 驱动100% Java 实现,直接通信主流(MySQL、Oracle 均用此类型)

开发中100% 使用第 4 类驱动

4. 核心依赖(以 MySQL 8.x 为例)

Maven 依赖(必须对应数据库版本):

<!-- MySQL 8.0+ 驱动 -->
<dependency>
    <groupId>com.mysql</groupId>
    <artifactId>mysql-connector-j</artifactId>
    <version>8.0.33</version>
</dependency>

驱动类全限定名:

  • MySQL 8.x:com.mysql.cj.jdbc.Driver
  • MySQL 5.x:com.mysql.jdbc.Driver

二、JDBC 核心 API(必须背熟)

所有操作都围绕以下 6 个核心接口/类:

类/接口包路径核心作用
DriverManagerjava.sql加载驱动、获取数据库连接
Connectionjava.sql数据库连接对象,管理事务、创建 Statement
Statementjava.sql执行静态 SQL 语句
PreparedStatementjava.sql执行预编译 SQL(推荐
CallableStatementjava.sql调用存储过程/函数
ResultSetjava.sql封装查询结果集
ResultSetMetaDatajava.sql获取结果集元数据(列名、类型、数量)
DataSourcejavax.sql连接池数据源(企业级标准)

三、JDBC 标准执行流程(固定 7 步)

这是 JDBC 最基础、最核心的执行模板,所有操作都遵循此流程

  1. 加载驱动(JDBC 4.0 后可自动加载)
  2. 获取数据库连接(Connection)
  3. 创建语句对象(Statement/PreparedStatement)
  4. 编写并执行 SQL
  5. 处理结果集(查询操作)
  6. 关闭资源(逆序关闭)
  7. 异常处理

标准代码示例(原生 JDBC)

import java.sql.*;

public class JdbcDemo {
    public static void main(String[] args) {
        // 1. 数据库连接信息
        String url = "jdbc:mysql://localhost:3306/testdb?useSSL=false&serverTimezone=UTC&allowPublicKeyRetrieval=true";
        String user = "root";
        String password = "123456";

        Connection conn = null;
        PreparedStatement pstmt = null;
        ResultSet rs = null;

        try {
            // 2. 获取连接
            conn = DriverManager.getConnection(url, user, password);

            // 3. 编写 SQL(预编译)
            String sql = "SELECT id, name, age FROM user WHERE age > ?";
            pstmt = conn.prepareStatement(sql);

            // 4. 设置参数
            pstmt.setInt(1, 18);

            // 5. 执行查询
            rs = pstmt.executeQuery();

            // 6. 处理结果集
            while (rs.next()) {
                int id = rs.getInt("id");
                String name = rs.getString("name");
                int age = rs.getInt("age");
                System.out.println(id + "-" + name + "-" + age);
            }

        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            // 7. 关闭资源(逆序关闭:ResultSet → Statement → Connection)
            try {
                if (rs != null) rs.close();
                if (pstmt != null) pstmt.close();
                if (conn != null) conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}

四、JDBC URL 格式(数据库连接串)

通用格式

jdbc:数据库类型://主机:端口/数据库名?参1=值&参数2=值

主流数据库 URL

  1. MySQL 8.x
jdbc:mysql://localhost:3306/数据库名?useSSL=false&serverTimezone=UTC&allowPublicKeyRetrieval=true&useUnicode=true&characterEncoding=utf8
  1. Oracle
jdbc:oracle:thin:@localhost:1521:ORCL
  1. SQLServer
jdbc:sqlserver://localhost:1433;DatabaseName=数据库名

MySQL 关键 URL 参数(必须掌握)

参数作用
useSSL关闭 SSL 连接(开发环境)
serverTimezone设置时区(UTC/Asia/Shanghai)
allowPublicKeyRetrieval允许公钥获取(解决连接报错)
useUnicode使用 Unicode 编码
characterEncoding字符集 utf8
autoReconnect自动重连

五、Connection 连接对象(核心)

1. 核心功能

  • 获取语句对象(createStatement/prepareStatement
  • 事务管理(提交、回滚、设置隔离级别)
  • 关闭连接

2. 事务相关方法

// 关闭自动提交(开启事务)
conn.setAutoCommit(false);

// 提交事务
conn.commit();

// 回滚事务
conn.rollback();

// 设置事务隔离级别
conn.setTransactionIsolation(Connection.TRANSACTION_REPEATABLE_READ);

// 设置只读(优化性能)
conn.setReadOnly(true);

3. 事务隔离级别(4 级)

从低到高:

  1. TRANSACTION_NONE:不支持事务
  2. TRANSACTION_READ_UNCOMMITTED:读未提交(脏读)
  3. TRANSACTION_READ_COMMITTED:读已提交(Oracle 默认)
  4. TRANSACTION_REPEATABLE_READ:可重复读(MySQL 默认)
  5. TRANSACTION_SERIALIZABLE:串行化(最高,性能最低)

并发问题:

  • 脏读:读到未提交数据
  • 不可重复读:同一事务两次查询结果不一致
  • 幻读:范围查询出现新增数据

六、Statement 家族(执行 SQL)

1. Statement(静态 SQL)

  • 执行无参数的静态 SQL
  • 缺点:SQL 注入风险、性能低、拼接繁琐
  • 不推荐生产使用
Statement stmt = conn.createStatement();
// 执行增删改
int rows = stmt.executeUpdate("DELETE FROM user WHERE id=1");
// 执行查询
ResultSet rs = stmt.executeQuery("SELECT * FROM user");

2. PreparedStatement(预编译 SQL,重点)

JDBC 首选语句对象,解决 Statement 所有问题:

  • 预编译,性能更高
  • 参数化,彻底防止 SQL 注入
  • 代码简洁,无需拼接 SQL
核心方法
// 创建对象
PreparedStatement pstmt = conn.prepareStatement(sql);

// 设置参数(索引从 1 开始)
pstmt.setInt(1, 10);
pstmt.setString(2, "张三");
pstmt.setDate(3, new Date(System.currentTimeMillis()));

// 执行
pstmt.executeUpdate(); // 增删改,返回受影响行数
pstmt.executeQuery();  // 查询,返回 ResultSet
pstmt.execute();       // 通用执行(了解)
批量执行(Batch)
pstmt = conn.prepareStatement("INSERT INTO user(name) VALUES(?)");
for (int i = 0; i < 1000; i++) {
    pstmt.setString(1, "name" + i);
    pstmt.addBatch(); // 添加到批量
}
pstmt.executeBatch(); // 执行批量

3. CallableStatement(调用存储过程)

用于执行数据库存储过程/函数

// 调用存储过程
CallableStatement cstmt = conn.prepareCall("{CALL 存储过程名(?,?)}");
cstmt.setInt(1, 10);
cstmt.registerOutParameter(2, Types.VARCHAR); // 注册输出参数
cstmt.execute();
String result = cstmt.getString(2);

七、ResultSet 结果集(查询数据)

1. 作用

封装 SELECT 查询返回的所有数据,以行为单位遍历

2. 遍历方式

// 向下移动一行,返回是否有数据
while (rs.next()) {
    // 获取数据:按列名 / 按列索引(从 1 开始)
    int id = rs.getInt("id");
    String name = rs.getString(2);
}

3. 常用获取方法

  • getInt() / getLong()
  • getString()
  • getDouble()
  • getDate() / getTime() / getTimestamp()
  • getObject():通用获取

4. 结果集类型(并发/滚动)

创建 Statement 时指定:

// 可滚动、敏感更新、只读
conn.createStatement(
    ResultSet.TYPE_SCROLL_INSENSITIVE,
    ResultSet.CONCUR_READ_ONLY
);
  • 滚动:前后移动、跳行
  • 敏感:数据变更是否实时反映到结果集

八、ResultSetMetaData 元数据

获取结果集结构信息,无需知道表结构:

ResultSetMetaData meta = rs.getMetaData();
// 列数量
int count = meta.getColumnCount();
// 列名
String name = meta.getColumnName(i);
// 列类型
String type = meta.getColumnTypeName(i);

九、JDBC 事务管理(重点)

1. 事务特性(ACID)

  • 原子性:要么全成功,要么全失败
  • 一致性:数据始终合法
  • 隔离性:多事务互不干扰
  • 持久性:提交后永久生效

2. JDBC 手动事务模板

Connection conn = null;
try {
    conn = getConnection();
    // 关闭自动提交
    conn.setAutoCommit(false);

    // 执行多个 SQL 操作
    update1();
    update2();

    // 提交
    conn.commit();
} catch (Exception e) {
    // 异常回滚
    if (conn != null) conn.rollback();
    e.printStackTrace();
} finally {
    close(conn);
}

十、数据库连接池(企业级必备)

1. 为什么要用连接池

原生 JDBC 缺点:

  • 频繁创建/关闭连接,性能极差
  • 资源消耗大,容易导致数据库崩溃

连接池优势:

  • 连接复用
  • 控制最大连接数
  • 提升性能、稳定性

2. 主流连接池

  1. HikariCP(SpringBoot 默认,性能最高)
  2. Druid(阿里,监控+风控)
  3. C3P0(老旧)
  4. DBCP(老旧)

3. DataSource 接口

连接池标准接口,企业开发必须用 DataSource 替代 DriverManager

Druid 连接池示例:

import com.alibaba.druid.pool.DruidDataSource;

public class DruidUtil {
    private static DruidDataSource dataSource;

    static {
        dataSource = new DruidDataSource();
        dataSource.setUrl("jdbc:mysql:///testdb");
        dataSource.setUsername("root");
        dataSource.setPassword("123456");
        // 核心配置
        dataSource.setInitialSize(5);    // 初始连接
        dataSource.setMaxActive(20);     // 最大连接
        dataSource.setMinIdle(5);        // 最小空闲
    }

    public static Connection getConnection() throws SQLException {
        return dataSource.getConnection();
    }
}

十一、JDBC 工具类封装(实战必备)

原生代码重复冗余,必须封装工具类:

import java.sql.*;

public class JdbcUtil {
    private static final String URL = "jdbc:mysql:///testdb?serverTimezone=UTC";
    private static final String USER = "root";
    private static final String PWD = "123456";

    // 静态加载驱动
    static {
        try {
            Class.forName("com.mysql.cj.jdbc.Driver");
        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        }
    }

    // 获取连接
    public static Connection getConn() {
        try {
            return DriverManager.getConnection(URL, USER, PWD);
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }

    // 关闭资源
    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();
        }
    }
}

十二、JDBC 批量处理(性能优化)

1. 适用场景

批量插入/更新大量数据(1000+ 条)。

2. 两种方式

  1. Statement 批量(不推荐)
  2. PreparedStatement 批量(推荐)

3. 开启 MySQL 批处理优化

URL 添加参数:

rewriteBatchedStatements=true

4. 批量代码

conn.setAutoCommit(false);
String sql = "INSERT INTO user(name) VALUES(?)";
pstmt = conn.prepareStatement(sql);

for (int i = 0; i < 1000; i++) {
    pstmt.setString(1, "test" + i);
    pstmt.addBatch();
}

pstmt.executeBatch();
conn.commit();

十三、JDBC 常见异常与解决方案

1. ClassNotFoundException

  • 原因:未导入驱动包 / 驱动类名写错
  • 解决:检查 Maven 依赖、驱动全类名

2. SQLException: Access denied

  • 原因:账号/密码错误
  • 解决:核对用户名密码

3. SQLException: Timezone

  • 原因:未指定时区
  • 解决:URL 加 serverTimezone=UTC

4. SQL 注入

  • 原因:使用 Statement 拼接 SQL
  • 解决:必须用 PreparedStatement

5. 连接泄漏

  • 原因:未关闭 Connection
  • 解决:finally 关闭 / 使用连接池

十四、JDBC 高级特性

1. 数据库主从复制(读写分离)

  • 写:主库
  • 读:从库
  • 通过动态切换 DataSource 实现

2. 分布式事务

跨多个数据库的事务,使用:

  • Seata
  • XA 协议
  • @GlobalTransactional

3. 大对象操作

  • CLOB:存储大文本
  • BLOB:存储二进制(图片、文件)
pstmt.setBlob(1, new FileInputStream("file.jpg"));

4. 滚动结果集

支持结果集向前、向后、跳行查询。


十五、JDBC 性能最佳实践(面试+实战)

  1. 必须使用 PreparedStatement,禁止 Statement
  2. 必须使用连接池,禁止原生 DriverManager
  3. 必须关闭资源,使用 try-with-resources 自动关闭
  4. 批量操作必须开启 rewriteBatchedStatements
  5. 查询只查需要的列,禁止 SELECT *
  6. 事务控制粒度尽可能小
  7. 合理设置连接池大小(CPU 核心数 * 2 + 磁盘数)
  8. 使用索引优化 SQL

十六、Java 7+ try-with-resources 优雅关闭资源

JDBC 实现了 AutoCloseable 接口,可自动关闭:

// 无需手动 finally 关闭,自动释放
try (Connection conn = JdbcUtil.getConn();
     PreparedStatement pstmt = conn.prepareStatement(sql);
     ResultSet rs = pstmt.executeQuery()) {
    // 业务逻辑
} catch (SQLException e) {
    e.printStackTrace();
}

十七、JDBC 与 ORM 框架关系

  • JDBC:底层标准,所有 ORM 框架都基于 JDBC
  • MyBatis:半自动化 ORM,手写 SQL
  • Hibernate/JPA:全自动化 ORM
  • Spring JdbcTemplate:JDBC 封装工具类

总结(核心必背)

  1. JDBC 是 Java 操作数据库的标准 API,核心是接口 + 驱动实现
  2. 固定流程:加载驱动 → 获取连接 → 创建语句 → 执行 SQL → 处理结果 → 关闭资源
  3. PreparedStatement 是最优选择,防注入、高性能
  4. 连接池是生产环境必备,推荐 HikariCP/Druid
  5. 事务通过 Connection 管理:关闭自动提交 → 提交/回滚
  6. 资源必须关闭,推荐 try-with-resources
  7. 性能优化:批量处理、只查需要列、连接复用