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

相关推荐
豌豆花下猫33 分钟前
Python 3.14 新特性盘点,更新了些什么?
后端·python·ai
caihuayuan51 小时前
Vue生命周期&脚手架工程&Element-UI
java·大数据·spring boot·后端·课程设计
明月与玄武4 小时前
Spring Boot中的拦截器!
java·spring boot·后端
菲兹园长4 小时前
SpringBoot统一功能处理
java·spring boot·后端
muxue1784 小时前
go语言封装、继承与多态:
开发语言·后端·golang
开心码农1号5 小时前
Go语言中 源文件开头的 // +build 注释的用法
开发语言·后端·golang
北极象5 小时前
Go主要里程碑版本及其新增特性
开发语言·后端·golang
lyrhhhhhhhh5 小时前
Spring框架(1)
java·后端·spring
喝养乐多长不高6 小时前
Spring Web MVC基础理论和使用
java·前端·后端·spring·mvc·springmvc
莫轻言舞7 小时前
SpringBoot整合PDF导出功能
spring boot·后端·pdf