JDBC:脏读/execute与executeQuery/update的区别/jdbc的不足/ResultSet

面试复盘:JDBC相关问题归纳

在最近的面试中,我遇到了几个关于JDBC的核心问题,这些问题不仅考察了对JDBC基础的理解,还涉及其局限性及解决方案。以下是问题的归纳与解答。

1. JDBC的脏读是什么?哪种隔离级别可以解决脏读?

脏读是什么?

脏读(Dirty Read)是数据库事务中的一种并发问题,指一个事务读取了另一个尚未提交事务修改的数据。如果该未提交事务回滚,读取到的数据就变成了"脏数据",导致不一致性。

示例:

  • 事务A将余额从100改为50,但未提交。
  • 事务B读取到余额为50。
  • 事务A回滚,余额恢复为100,但事务B已基于"脏数据"50执行操作。

解决脏读的隔离级别:

JDBC通过Connection.setTransactionIsolationLevel()设置事务隔离级别。脏读可以通过以下隔离级别解决:

  • Read Committed(读已提交): 确保只能读取已提交的数据,解决了脏读问题。但可能出现不可重复读。
  • 更高的隔离级别(如Repeatable Read或Serializable)也能解决,但性能开销更大。

结论: Read Committed 是最低解决脏读的隔离级别,常用且平衡了性能与一致性。


2. JDBC中的execute、executeQuery、executeUpdate有什么区别?

JDBC提供了三种执行SQL的方法,区别如下:

  • execute()

    • 用途: 通用的SQL执行方法,适用于任何SQL语句(查询、更新、DDL等)。
    • 返回值: boolean,true表示返回结果集(如SELECT),false表示无结果集(如UPDATE)。
    • 使用场景: 不确定SQL类型时使用,需后续调用getResultSet()getUpdateCount()处理结果。
  • executeQuery()

    • 用途: 专门执行查询语句(如SELECT)。
    • 返回值: ResultSet,直接返回查询结果集。
    • 使用场景: 明确需要查询数据时使用,简洁高效。
  • executeUpdate()

    • 用途: 执行更新操作(如INSERT、UPDATE、DELETE)或DDL语句。
    • 返回值: int,表示受影响的行数。
    • 使用场景: 修改数据库时使用,不返回结果集。

总结:

  • execute:万能但复杂。
  • executeQuery:查询专用。
  • executeUpdate:更新专用。

3. JDBC的不足之处是什么?MyBatis是如何解决的?

JDBC的不足:

  1. 代码冗余: 手动编写SQL、获取连接、关闭资源,重复性高。
  2. SQL硬编码: SQL语句写在Java代码中,维护困难,难以动态调整。
  3. 结果映射繁琐: 从ResultSet手动映射到对象,容易出错且效率低。
  4. 异常处理复杂: SQLException需要频繁try-catch,代码臃肿。
  5. 缺乏缓存支持: JDBC本身不提供查询缓存,性能优化受限。

MyBatis如何解决:

  1. 简化开发: 通过XML或注解配置SQL,减少样板代码。
  2. SQL分离: SQL语句与Java代码解耦,维护更方便,支持动态SQL。
  3. 自动映射: 提供结果集到Java对象的自动映射,减少手动转换。
  4. 资源管理: 集成连接池,自动管理数据库连接。
  5. 缓存支持: 内置一级缓存(SqlSession级别)和二级缓存,提升性能。

结论: MyBatis在JDBC基础上封装了持久层操作,极大提高了开发效率和灵活性。


4. JDBC的ResultSet是什么?

定义:

ResultSet 是JDBC中表示数据库查询结果的对象,由executeQuery()返回。它本质是一个游标,指向查询返回的数据行,允许逐行读取数据。

特点:

  • 游标移动: 默认只能向前移动(next()),支持双向移动(TYPE_SCROLL_INSENSITIVE)。
  • 数据访问: 通过getXXX()方法(如getInt()、getString())按列名或索引读取数据。
  • 生命周期: 与Statement和Connection绑定,关闭任一都会导致ResultSet不可用。

示例:

java 复制代码
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("SELECT id, name FROM users");
while (rs.next()) {
    int id = rs.getInt("id");
    String name = rs.getString("name");
    System.out.println(id + ": " + name);
}
rs.close();
stmt.close();

类型与并发性:

  • 类型: 只读(CONCUR_READ_ONLY)或可更新(CONCUR_UPDATABLE)。
  • 滚动性: 只向前(TYPE_FORWARD_ONLY)或可滚动(TYPE_SCROLL_SENSITIVE)。

作用: ResultSet 是JDBC查询的核心桥梁,将数据库数据传递给Java程序。


总结

这些问题涵盖了JDBC的核心概念(事务、执行方法、结果集)及其局限性。通过对比MyBatis,可以看出JDBC虽基础但功能有限,现代框架在生产中更受欢迎。复盘这些问题让我对JDBC的理解更加深入,也为后续优化代码提供了思路。

相关推荐
bobz96531 分钟前
windows 配置 conda 环境变量
后端
回家路上绕了弯1 小时前
线程池优化实战:从性能瓶颈到极致性能的演进之路
java·后端
bobz9651 小时前
pycharm pro 安装插件失败
后端
丘山子2 小时前
如何规避 A/B Testing 中的致命错误?何时进行 A/B 测试?
前端·后端·面试
用户84913717547163 小时前
JDK 17 实战系列(第4期):安全性与稳定性增强详解
java·后端·性能优化
苏三的开发日记3 小时前
centos如何使用高版本gcc
后端
自由的疯3 小时前
java程序员怎么从Python小白变成Python大拿?(三)
java·后端·trae
用户84913717547163 小时前
JustAuth实战系列(第4期):模板方法模式实战 - AuthDefaultRequest源码剖析
java·后端·架构
lynnss_ai3 小时前
Go + GORM 实现支持嵌套事务的中间件(含事务计数器与日志开关)
后端
_風箏3 小时前
OpenSSH【安装 02】离线升级异常问题解决、无法升级时的失败恢复
后端