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的理解更加深入,也为后续优化代码提供了思路。

相关推荐
盛瑄妍1 分钟前
Assembly语言的云计算
开发语言·后端·golang
慕容蕴秋5 分钟前
Perl语言的计算机网络
开发语言·后端·golang
慕容靖翾7 分钟前
Lua语言的无线通信
开发语言·后端·golang
哪吒编程10 分钟前
新项目终于用上了jdk24
java·后端
倚栏听风雨24 分钟前
Java中的Type详解
后端
梅一一29 分钟前
一个b站偷懒工具
javascript·后端
东方韡璟33 分钟前
Simula语言的正则表达式
开发语言·后端·golang
这里有鱼汤38 分钟前
面向Web开发者的Python速成指南,5分钟学会Python
后端·python
CHSnake44 分钟前
设计HTTP和gRPC错误码.md
后端·go
刀法如飞44 分钟前
DDD领域驱动设计详解-Java/Go/JS/Python实现
java·前端·后端