引言
在现代企业级应用开发中,持久层框架(如 MyBatis、Hibernate 等)极大地简化了数据库操作,提高了开发效率和代码的可维护性。本文将通过一个最简单的示例,演示如何使用 JDBC 连接数据库、执行 SQL 语句以及处理结果,并与Mybatis源码做对比,为后续深入研究 MyBatis 源码打下基础。
通过 JDBC 查询数据
在这个例子中,我们将使用 MySQL 数据库作为示例,看一下传统的 JDBC 方式是如何执行一个简单的查询操作的,
以下代码是我们《从零开始实现MyBatis框架》的第一个类SqlSession以及selectOne方法,代码如下:
package org.apache.ibatis.session;
import java.sql.*;
/**
* Sql会话
*
* @author crazy coder
* @since 2024/10/07
**/
public class SqlSession {
public String selectOne(Long id) {
// 1. 定义数据源信息:驱动、数据库连接 URL、数据库用户名、数据库密码
String driver = "com.mysql.cj.jdbc.Driver";
String url = "jdbc:mysql://localhost:3306/mybatis?useSSL=false&serverTimezone=UTC";
String user = "root";
String password = "root";
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
// 2. 加载 MySQL JDBC 驱动
Class.forName(driver);
// 3. 获取数据库连接
conn = DriverManager.getConnection(url, user, password);
// 4. 准备 SQL 语句、预编译 SQL语句
String sql = "select `id`, `username`, `email` from `author` where id = ? ";
pstmt = conn.prepareStatement(sql);
// 5. 设置参数
pstmt.setLong(1, id);
// 6. 执行 SQL 查询操作
rs = pstmt.executeQuery();
// 7. 处理结果集
StringBuilder result = new StringBuilder();
while (rs.next()) {
result.append("id: ").append(rs.getInt("id"))
.append(", username: ").append(rs.getString("username"))
.append(", email: ").append(rs.getString("email"));
}
return result.toString();
} catch (ClassNotFoundException | SQLException e) {
e.printStackTrace();
} finally {
// 8. 关闭资源
if (pstmt != null) {
try {
pstmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (rs != null) {
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
return "";
}
}
这段代码展示了如何使用 JDBC 进行一个简单的查询操作。可以看到,我们需要手动加载 JDBC 驱动、获取连接、创建预编译语句、设置参数、执行查询,并处理结果集。此外,还需要注意资源的关闭问题。
代码关键步骤说明如下:
- 定义数据源信息:包括驱动、数据库连接 URL、数据库用户名、数据库密码;
- 加载驱动:使用 Class.forName() 方法加载 MySQL 的 JDBC 驱动。这是为了确保 JVM 知道如何处理 MySQL
数据库的连接请求; - 建立连接:通过 DriverManager.getConnection() 方法建立数据库连接。需要提供数据库的 URL、用户名和密码;
- 预编译 SQL语句:定义一个 SQL查询语句,并使用 PreparedStatement 来执行。PreparedStatement
允许你预编译 SQL 语句,并安全地设置参数; - 设置参数:通过 setLong() 方法设置 SQL 语句中的参数值;
- 执行 SQL 语句:使用 executeQuery() 方法执行 SQL查询操作;
- 处理结果集:这里只是简单的讲结果拼接成字符串返回;
- 关闭资源:无论是否成功执行 SQL,都应该在 finally 块中关闭 PreparedStatement 、ResultSet 和
Connection 对象,以释放资源。
传统的 JDBC 方式有哪些缺点
通过以上示例。我们可以发现,使用 JDBC 方式查询数据存在一些不便之处,这些不便主要体现在代码的复杂性、重复性、易错性和维护成本等方面。
-
代码复杂性高
使用 JDBC 编写 SQL 查询通常需要手动处理很多细节,包括加载 JDBC 驱动、建立数据库连接、创建 PreparedStatement、设置参数、执行查询、处理结果集等。这使得代码量较大,结构相对复杂。 -
代码重复性高
由于每执行一次数据库操作都需要编写类似的代码片段(如连接数据库、关闭资源等),这导致了大量的代码重复,增加了维护难度。 -
易犯错误
手动处理数据库连接、异常处理、资源关闭等操作容易出错,比如忘记关闭连接或结果集,导致内存泄漏等问题。 -
缺乏类型安全
使用 JDBC 时,处理结果集通常需要手动转换为 Java 对象,这可能导致类型转换错误。此外,SQL 语句中的字段名和 Java 对象中的属性名不一致也可能引发问题。 -
缺少自动映射功能
JDBC 不提供自动的 ORM(对象关系映射)功能,所有结果集到 Java 对象的映射都需要手动实现。 -
事务管理繁琐
在 JDBC 中,事务管理通常需要手动开始事务、提交或回滚事务,而在复杂的业务逻辑中,事务的嵌套管理会变得更加复杂。 -
缺少缓存机制
JDBC 本身不支持缓存机制,而 MyBatis 支持一级缓存(本地缓存)和二级缓存,可以显著提升查询性能。
与Mybatis源码对比
接下来,我们将看看 MyBatis 是如何完成同样的查询任务。MyBatis 通过抽象出 Configuration、SqlSession、Executor等组件,简化了数据库操作的流程,在后续的文章中,我们将继续深入探讨 MyBatis 的更多细节和内部机制,帮助读者更好地理解和使用 MyBatis。