原生JDBC的开发步骤有哪些?

来源:Oracle教程作者:长沙网站建设头衔:草根站长
导读:本期聚焦于小伙伴创作的《原生JDBC的开发步骤有哪些?》,敬请观看详情。在一个典型的Java工程中,从数据持久化到报表查询,几乎都绕不开与数据库的交互。JDBC(Java Database Connectivity)作为Java访问关系型数据库的底层API,定义了连接、执行SQL、处理结果的标准流程。掌握原生JDBC的开发步骤,不仅是理解Hibernate、MyBatis等ORM框架的基石,也有助于在特定场景下写出更高效的数据库操作代码。这套步骤围绕DriverManager、Connection、Statement、ResultSet等核心接口展开,涵盖驱动注册、连接建立、语句创建、SQL执行、结果遍历及资源释放六个关键环节。每一步都有其必须遵守的规范,例如资源关闭顺序、SQL注入预防等,本文将结合代码实例逐一细说。

原生JDBC的开发步骤有哪些?

JDBC是一套由Java语言编写的类和接口,位于java.sql和javax.sql包中,它为多种关系数据库提供了统一的访问方式。数据库厂商根据JDBC规范实现对应的驱动程序,开发者只需按标准API编码,即可屏蔽底层差异。了解原生开发流程,对后续学习连接池、分布式事务等高级特性也大有裨益。下面我们从核心组件开始,逐步拆解完整的开发步骤。

JDBC核心接口与执行流程

JDBC定义了四个最关键的核心接口:DriverConnectionStatementResultSet。其中Driver接口由数据库厂商实现,负责与具体的数据库通信;Connection代表一个数据库连接会话;Statement用于将SQL语句发送到数据库执行;ResultSet则封装了查询返回的结果集。此外,辅助类DriverManager负责管理已注册的驱动,并根据URL选择合适的驱动来建立连接。

在实际操作中,开发人员接触最多的是ConnectionStatementResultSet。为了预防SQL注入,更推荐使用PreparedStatement(继承自Statement),它能对SQL语句进行预编译并支持参数化查询。整个工作流为:加载驱动 → 获取连接 → 创建执行语句 → 执行SQL并处理结果 → 释放资源。这五个步骤缺一不可,尤其是资源释放环节,若处理不当很容易造成数据库连接泄露,进而拖垮整个应用。

下面是一段完整的原生JDBC查询示例,它遵循了上述流程,并通过try-with-resources自动关闭资源:

public List<User> queryUsers(String keyword) {
    String url = "jdbc:mysql://localhost:3306/test?useSSL=false";
    String user = "root";
    String password = "123456";
    String sql = "SELECT id, name, email FROM users WHERE name LIKE ?";
    List<User> users = new ArrayList<>();
    try (Connection conn = DriverManager.getConnection(url, user, password);
         PreparedStatement ps = conn.prepareStatement(sql)) {
        ps.setString(1, "%" + keyword + "%");
        try (ResultSet rs = ps.executeQuery()) {
            while (rs.next()) {
                User u = new User();
                u.setId(rs.getInt("id"));
                u.setName(rs.getString("name"));
                u.setEmail(rs.getString("email"));
                users.add(u);
            }
        }
    } catch (SQLException e) {
        e.printStackTrace();
    }
    return users;
}

这段代码从连接建立到结果封装一气呵成,展示了最常用的PreparedStatement模式。接下来我们详细拆解其中的每一步。

原生JDBC开发步骤详解

第一步:加载与注册驱动

在JDBC 4.0之前,开发者必须显式调用Class.forName()来加载驱动类,例如Class.forName("com.mysql.cj.jdbc.Driver")。这会触发驱动类中的静态初始化代码,将自身注册到DriverManager中。从JDBC 4.0开始(随Java 6发布),引入了服务提供者机制(SPI),只要驱动的JAR包中包含了META-INF/services/java.sql.Driver文件,DriverManager就能自动发现并注册驱动,因此显式加载不再是必须的。但为了兼容旧环境或某些非标准驱动,仍建议保留该调用。

驱动注册本质上就是将驱动实例添加到DriverManager内部的registeredDrivers列表中。当调用getConnection()时,DriverManager会遍历该列表,依次询问每个驱动是否能够处理传入的URL,第一个返回成功连接的驱动即被使用。这一机制让程序无需硬编码数据库类型,更换数据库时只需替换驱动JAR和URL即可。

第二步:建立数据库连接

通过DriverManager.getConnection(url, user, password)即可获得一个Connection对象。URL的格式为jdbc:子协议:子名称,例如jdbc:mysql://localhost:3306/dbname。参数可以携带各种配置,如useSSL=falseserverTimezone=Asia/Shanghai等,不同数据库的参数差异较大。

获取到的连接是稀缺资源,每次物理连接的开销都很大,因此生产环境中通常结合连接池(如HikariCP、Druid)来复用连接,但在原生JDBC开发中,为了演示清晰,我们直接创建。务必在操作完成后立即关闭连接,否则会出现连接泄露。Java 7引入的try-with-resources语法能够确保Connection在被使用后自动调用close(),极大简化了资源管理。

第三步:创建Statement或PreparedStatement对象

Statement用于执行静态SQL语句,通常没有参数。但绝大部分场景下,建议使用PreparedStatement,它具备三大优势:一是防止SQL注入,因为参数值会被预编译和转义;二是对于重复执行的SQL语句,预编译能提高性能;三是代码可读性更好。创建方式为conn.prepareStatement(sql),SQL中使用问号占位,随后通过setXxx(index, value)方法设置参数,索引从1开始。

如果需要在插入数据后返回自增主键,可以在创建PreparedStatement时指定Statement.RETURN_GENERATED_KEYS标志,然后通过ps.getGeneratedKeys()获取主键值。

String insertSQL = "INSERT INTO users(name, email) VALUES(?, ?)";
try (Connection conn = DriverManager.getConnection(url, user, password);
     PreparedStatement ps = conn.prepareStatement(insertSQL, Statement.RETURN_GENERATED_KEYS)) {
    ps.setString(1, "张三");
    ps.setString(2, "zhang@ippipp.com");
    int affectedRows = ps.executeUpdate();
    if (affectedRows > 0) {
        try (ResultSet rs = ps.getGeneratedKeys()) {
            if (rs.next()) {
                long generatedId = rs.getLong(1);
                System.out.println("插入成功,主键ID:" + generatedId);
            }
        }
    }
}

第四步:执行SQL语句

Statement接口提供了三种执行方法:executeQuery()用于SELECT查询,返回ResultSetexecuteUpdate()用于INSERT、UPDATE、DELETE等DML语句,返回受影响的行数(int);execute()可用于执行任何SQL,返回布尔值表示是否返回ResultSet,然后通过getResultSet()获取结果。日常开发中最常用的是前两种。

执行查询时,必须正确处理ResultSet。它以游标方式指向结果行,初始时游标位于第一行之前,调用next()方法可将游标移动到下一行,并返回布尔值表示是否到达数据集末尾。典型的遍历模式为while(rs.next()),每次循环通过列名或索引取值。注意,列索引也是从1开始,但因为列顺序可能因表结构变化而改变,推荐使用列名获取值,如rs.getString("name")

第五步:释放资源

资源释放的顺序与创建顺序相反,即先关闭ResultSet,再关闭Statement,最后关闭Connection。每个close操作都应独立进行,避免前面的close抛出异常导致后续资源无法释放。在Java 7之前,需要在finally块中手工关闭,代码十分冗长;采用try-with-resources后,只要资源实现了AutoCloseable接口,便会按照声明的相反顺序自动关闭,代码更加安全和简洁。

需要特别注意的是,ResultSetStatement的关闭并不会自动关闭底层数据库连接;若使用连接池,Connection的关闭是返还给池中,而非物理断开。如果忘记关闭StatementResultSet,可能会影响连接池中连接的回收,逐渐耗尽资源。因此,养成良好的资源管理习惯至关重要。

事务控制与异常处理

默认情况下,JDBC连接处于自动提交模式,每执行一条SQL语句都会立即提交到数据库。为了保持多个操作的原子性,必须手动开启事务。通过conn.setAutoCommit(false)关闭自动提交,此时所有SQL都在同一个事务中,直到调用conn.commit()conn.rollback()。需要注意的是,事务结束时应当恢复自动提交状态,以避免影响连接复用时的事务行为。

异常处理同样是原生JDBC编程中的重点。所有数据库操作都可能抛出SQLException,其中包含错误码、SQL状态等信息。捕获异常后应执行回滚,并妥善记录日志。以下是一个完整的事务管理示例:

public void transfer(int fromId, int toId, double amount) {
    String url = "jdbc:mysql://localhost:3306/test";
    String user = "root";
    String password = "123456";
    Connection conn = null;
    try {
        conn = DriverManager.getConnection(url, user, password);
        conn.setAutoCommit(false);
        // 扣款
        try (PreparedStatement ps1 = conn.prepareStatement("UPDATE account SET balance = balance - ? WHERE id = ?")) {
            ps1.setDouble(1, amount);
            ps1.setInt(2, fromId);
            ps1.executeUpdate();
        }
        // 加款
        try (PreparedStatement ps2 = conn.prepareStatement("UPDATE account SET balance = balance + ? WHERE id = ?")) {
            ps2.setDouble(1, amount);
            ps2.setInt(2, toId);
            ps2.executeUpdate();
        }
        conn.commit();
    } catch (SQLException e) {
        if (conn != null) {
            try {
                conn.rollback();
            } catch (SQLException ex) {
                ex.printStackTrace();
            }
        }
        e.printStackTrace();
    } finally {
        if (conn != null) {
            try {
                conn.setAutoCommit(true); // 恢复默认
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}

使用try-with-resources时,由于资源在代码块结束时关闭,而commit/rollback需要在关闭前执行,因此连接不能直接放在try的括号中,必须像上面那样单独管理。另一种做法是使用事务管理工具或AOP进行统一控制,但原生JDBC中的这些基础写法有助于理解事务边界。

通过以上步骤,我们已经完整掌握了原生JDBC的开发流程。虽然在实际项目中很少直接手写这些模板代码(更常用Spring JDBC或ORM框架),但只有理解底层机制,才能在出现性能问题或复杂查询时做出更精准的决策。

原生JDBCJDBC开发步骤数据库连接修改时间:2026-08-12 20:42:53

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。