当前位置: 首页 > news >正文

JDBC教程,2025版最新讲解.超详细入门教程

以下内容全面详尽地梳理了 JDBC (Java Database Connectivity)的核心知识点,并在关键环节配以示例代码。若要快速定位,可先查看下方结构:

  1. JDBC 概览
  2. 驱动加载与注册
  3. 获取数据库连接
  4. 执行 SQL(Statement、PreparedStatement、CallableStatement)
  5. 处理结果集(ResultSet)
  6. 批量操作与批处理
  7. 事务管理
  8. 元数据操作(DatabaseMetaData、ResultSetMetaData)
  9. 异常处理
  10. 连接池与 DataSource
  11. 最佳实践与性能优化

1. JDBC 概览

  • 用途:提供 Java 程序访问各种关系型数据库(MySQL、Oracle、PostgreSQL 等)的统一 API。
  • 核心接口包java.sql.*
  • 主要角色
    • DriverManager/Driver:驱动注册、连接分发
    • Connection:管理会话、事务
    • Statement/PreparedStatement/CallableStatement:执行 SQL
    • ResultSet:承载查询结果
    • DataSource:替代 DriverManager 的连接获取方式(可集成连接池)

执行过程可总结为:

  1. 驱动加载(现在可以省略)
  2. 获取数据库连接
  3. 定义要执行的sql语句
  4. 获取执行对象
  5. 执行对象执行sql语句,获取返回结果
  6. 后续处理

2. 驱动加载与注册

2.1 自动注册(JDBC 4.0+)

只要在 classpath 中包含相应数据库的 JDBC 驱动(如 mysql-connector-java.jar),Driver 会通过 SPI 自动注册,无需显式调用。

// 不需要 Class.forName(...),直接拿连接即可
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/testdb", "root", "password");

2.2 手动加载(向后兼容)

Class.forName("com.mysql.cj.jdbc.Driver");
// 或者老版本
// Class.forName("com.mysql.jdbc.Driver");

3. 获取数据库连接

String url      = "jdbc:mysql://localhost:3306/testdb?useSSL=false&serverTimezone=UTC";
String user     = "root";
String password = "password";try (Connection conn = DriverManager.getConnection(url, user, password)) {// 使用 conn 
} catch (SQLException e) {e.printStackTrace();
}
  • 常用参数
    • useSSL=false:禁用 SSL
    • serverTimezone=UTC:指定时区
    • autoReconnect=true:自动重连

当然可以,以下是重新整理并扩充后的第4部分内容,加入了 SQL 注入的讲解,并对 Statement 的两个方法做了深入分析,保持原有结构和风格:


4. 获取执行 SQL 对象,Cnn 获取

在 JDBC 中,获取数据库连接后,我们需要通过执行 SQL 语句与数据库交互,这一过程通常通过以下三种执行对象实现:

  • Statement:用于执行静态 SQL 语句(不带参数),简单但易受 SQL 注入攻击;
  • PreparedStatement:预编译 SQL 语句,支持参数绑定,性能更优、安全性更高;

Statement 的核心方法:

int executeUpdate(String sql)
  • 执行 DML(INSERT、UPDATE、DELETE)DDL(CREATE、DROP)
  • 返回值为 受影响的行数,若为 DDL,通常返回 0(不代表失败)。
ResultSet executeQuery(String sql)
  • 执行 DQL(SELECT)语句,返回查询结果集 ResultSet

关于 SQL 注入(SQL Injection)

SQL 注入是一种严重的安全漏洞,攻击者可以通过拼接恶意 SQL 来操控数据库。例如:

String name = "' OR '1'='1";
String sql = "SELECT * FROM user WHERE name = '" + name + "'";

构造出的 SQL 实际是:

SELECT * FROM user WHERE name = '' OR '1'='1'

where后面的结果将永远是真的,所以就可以永远的查询出来.
将返回所有用户数据,甚至可用于删除表结构,极其危险!


4.1 Statement(不预编译,易受 SQL 注入)

String name = "张三";
String sql = "SELECT id, name FROM user WHERE name = '" + name + "'";
try (Statement stmt = conn.createStatement();ResultSet rs = stmt.executeQuery(sql)
) {while (rs.next()) {System.out.println(rs.getInt("id") + ": " + rs.getString("name"));}
}

优点:简单,适合一次性、非常简单的 SQL;
缺点:拼接字符串,极易受 SQL 注入攻击不能复用或预编译,性能差。


4.2 PreparedStatement(预编译,防注入、性能更优)

String sql = "SELECT id, name FROM user WHERE name = ? AND age > ?";
try (PreparedStatement pstmt = conn.prepareStatement(sql)) {pstmt.setString(1, "张三");pstmt.setInt(2, 18);try (ResultSet rs = pstmt.executeQuery()) {while (rs.next()) {System.out.println(rs.getInt("id") + ": " + rs.getString("name"));}}
}

优点:

  • 使用 占位符 ? 实现参数绑定,不拼接字符串,有效防止 SQL 注入
  • SQL 会被 预编译并缓存,适合多次执行,提高效率
  • 自动转义字符串,避免因特殊字符出错

缺点:相比 Statement 书写稍复杂,不适合拼接动态结构的 SQL(如条件列名)。


Statement vs PreparedStatement 详细对比

特性StatementPreparedStatement
SQL 预编译是(可缓存执行计划)
防 SQL 注入能力差(需要手动拼接字符串)强(使用参数绑定)
性能(重复执行场景)差(每次都解析)优(执行计划可复用)
可读性与维护性差(大量拼接容易混乱)高(结构清晰,安全)
支持占位符 ?
使用场景简单、临时查询正式项目、复杂参数、安全性要求高场合

5. 处理结果集(ResultSet)

  • 指针导航.next(), .first(), .last(), .absolute(n)(需指定 TYPE_SCROLL)
  • 获取列值getInt(), getString(), getDate()
  • 按列名或列索引
  • 类型转换注意:避免隐式类型转换带来的性能/精度问题
ResultSet rs = pstmt.executeQuery();
while (rs.next()) {int    id   = rs.getInt(1);String name = rs.getString("name");Date   dob  = rs.getDate("dob");// ...
}

6. 批量操作与批处理

批量执行可显著提升大量插入/更新的性能。

String sql = "INSERT INTO user(name, age) VALUES(?, ?)";
try (PreparedStatement pstmt = conn.prepareStatement(sql)) {conn.setAutoCommit(false);  // 关闭自动提交for (int i = 1; i <= 1000; i++) {pstmt.setString(1, "User" + i);pstmt.setInt(2, 20 + (i % 30));pstmt.addBatch();if (i % 200 == 0) {pstmt.executeBatch();conn.commit();  // 分批提交}}// 提交剩余pstmt.executeBatch();conn.commit();
}

7. 事务管理Cnn对象负责管理

try {conn.setAutoCommit(false);  // 开启事务// 操作1// 操作2// ...conn.commit();              // 提交事务
} catch (SQLException e) {conn.rollback();            // 回滚事务
} finally {conn.setAutoCommit(true);   // 恢复默认
}
  • 隔离级别conn.setTransactionIsolation(...)
  • 保存点Savepoint sp = conn.setSavepoint("sp1"); conn.rollback(sp);

8. 元数据操作

8.1 DatabaseMetaData

DatabaseMetaData dbMeta = conn.getMetaData();
System.out.println("Database product: " + dbMeta.getDatabaseProductName());
System.out.println("Driver version: " + dbMeta.getDriverVersion());

8.2 ResultSetMetaData

ResultSetMetaData rsMeta = rs.getMetaData();
int columnCount = rsMeta.getColumnCount();
for (int i = 1; i <= columnCount; i++) {System.out.println("Column " + i + ": " + rsMeta.getColumnName(i)+ " (" + rsMeta.getColumnTypeName(i) + ")");
}

9. 异常处理

  • SQLException
    • .getErrorCode():数据库错误码
    • .getSQLState():标准 SQLState
  • 资源释放:强烈推荐使用 try-with-resources 自动关闭 ConnectionStatementResultSet
try (Connection conn =;PreparedStatement pstmt = conn.prepareStatement(...);ResultSet rs = pstmt.executeQuery();
) {// ...
} catch (SQLException e) {System.err.println("Error Code: " + e.getErrorCode());System.err.println("SQL State : " + e.getSQLState());e.printStackTrace();
}

10. 连接池与 DataSource

10.1 为什么使用连接池

  • 连接创建开销大
  • 重复使用可提升性能

10.2 常见连接池

  • HikariCP(高性能)
  • Apache DBCP
  • C3P0

10.3 DataSource 示例(HikariCP)

HikariConfig config = new HikariConfig();
config.setJdbcUrl("jdbc:mysql://localhost:3306/testdb");
config.setUsername("root");
config.setPassword("password");
config.setMaximumPoolSize(10);DataSource ds = new HikariDataSource(config);// 获取连接
try (Connection conn = ds.getConnection()) {// ...
}

11. 最佳实践与性能优化

  1. 使用 PreparedStatement 防止 SQL 注入、提升性能。
  2. 合理设置批量大小,避免长事务占用资源。
  3. 关闭不必要的自动提交,批量操作时手动管理事务。
  4. 使用连接池,避免频繁创建销毁连接。
  5. 定期监控慢查询,并为频繁访问的字段添加索引。
  6. 尽量只查询所需列,避免 SELECT *
  7. 及时关闭资源,防止连接泄漏(try-with-resources)。

IDEA调试总结:

更通俗、贴近实际编程操作的语言来重新解释 IntelliJ IDEA 中调试时常用的快捷键,避免术语,让你一看就懂:


IDEA 调试快捷键(简单易懂版)

功能Windows / LinuxmacOS说明(通俗解释)
启动调试Shift + F9Control + D像运行程序一样运行,但可以中途停下来看代码状态
停止调试Ctrl + F2Command + F2停掉整个程序
一步一步执行代码(当前行)F8F8当前行执行完再停在下一行(如果是循环,就跳下一次)
进入方法体中去看具体执行F7F7如果当前行是一个函数调用,按它会跳进去函数里看细节
跳出当前方法返回上一层Shift + F8Shift + F8如果你已经进了方法里,按这个会回到调用这个方法的地方
执行到光标处停下Alt + F9Option + F9让程序一直跑到你当前鼠标点的位置再停下(省得一直按F8)
继续往下执行程序F9Command + Option + RF9程序继续往下跑,直到遇到下一个断点
设置或取消断点Ctrl + F8Command + F8在代码左边点一下,红点就是断点,程序会在这里暂停

常用调试辅助操作

功能Windows / LinuxmacOS说明
查看某个变量的值鼠标悬停鼠标悬停把鼠标放在变量上面,就会显示它当前的值
手动输入表达式查看结果Alt + F8Option + F8弹出一个窗口,你可以输入变量或表达式看结果,比如 a + b
查看所有断点Ctrl + Shift + F8Command + Shift + F8可以集中管理所有断点
快速查看变量内容Ctrl + Shift + ICommand + Shift + I不用跳转,临时查看变量内容

举个简单例子:

public class Demo {public static void main(String[] args) {int a = 10;int b = 20;int c = add(a, b);  // 👉 在这里打断点System.out.println("结果是:" + c);}public static int add(int x, int y) {return x + y;}
}

如果你在 int c = add(a, b); 那一行打断点:

  • Shift + F9 开始调试;
  • 程序会停在 add(a, b) 那一行;
  • F8,它会直接执行完这一行然后到下一行;
  • F7,它会跳进 add() 方法里面
  • 在方法中可以继续按 F8 看一步步怎么返回结果;
  • 再按 Shift + F8 就可以返回到 main() 继续调试;
  • 最后按 F9 可以直接让程序跑完。

如果你还不熟练,可以先只记住这两个:

  • 👉 F8一步一步往下执行
  • 👉 F7进入函数体里看看里面是怎么执行的

http://www.dtcms.com/a/299574.html

相关文章:

  • 从UX到AX:从“设计路径”到“共创关系”的范式革命——Agentic Experience如何重塑未来产品哲学
  • 关于Feign的应用
  • 大话数据结构之<队列>
  • PHP框架之Laravel框架教程:1. laravel搭建
  • 方案C,version1
  • 零基础学习性能测试第四章:从0到1学会编写性能测试报告
  • 如何开始学习和使用 BPF/eBP
  • 树上倍增和LCA问题
  • python—————knn算法
  • C++:STL中vector的使用和模拟实现
  • 计算机网络体系结构的核心思想是什么?它有什么用?
  • 大语言模型困惑度:衡量AI语言能力的核心指标
  • 数据结构自学Day15 -- 非比较排序--计数排序
  • MySQL相关概念和易错知识点(2)(表结构的操作、数据类型、约束)
  • 推荐系统(第三课第二周)
  • Deepseek要凉了吗?
  • go-admin 构建arm镜像
  • 基于遗传算法的多无人车协同侦察与安全保护策略优化
  • Java 封装、继承与多态:从基础到实践的核心思想
  • TypeScript 中的 typeof
  • 【17】C# 窗体应用WinForm ——【文本框TextBox、富文本框RichTextBox 】属性、方法、实例应用
  • SpringBoot总结
  • 秋招Day19 - 分布式 - 限流
  • VUE2 学习笔记7 v-model、过滤器
  • 各种前端框架界面
  • ARM SMMUv3控制器注册过程分析(八)
  • odoo代码分析(一)
  • 以太坊下一阶段的关键——隐私
  • 根本是什么
  • Transformer:颠覆NLP的自注意力革命