JDBC:Java数据库连接的基石
JDBC (Java Database Connectivity) 是Java平台提供的用于执行SQL语句的API,它是所有Java数据库操作技术的基础,理解JDBC的工作流程对于深入理解后续的高级框架至关重要,一个典型的JDBC查询过程包含以下几个核心步骤:

-
加载驱动:在早期版本中,需要显式加载数据库驱动类,如
Class.forName("com.mysql.cj.jdbc.Driver"),从JDBC 4.0开始,只要驱动JAR包在类路径下,驱动程序会自动注册,此步骤通常可以省略。 -
建立连接:通过
DriverManager类获取一个数据库连接对象Connection,这需要提供数据库的URL、用户名和密码。String url = "jdbc:mysql://localhost:3306/your_database?useSSL=false&serverTimezone=UTC"; String user = "username"; String password = "password"; Connection conn = DriverManager.getConnection(url, user, password);
-
创建Statement对象:通过
Connection对象创建Statement或PreparedStatement。Statement用于执行静态SQL语句,而PreparedStatement用于执行预编译的SQL语句,是更推荐的方式。 -
执行查询:使用
Statement或PreparedStatement对象的executeQuery()方法执行SELECT语句,该方法会返回一个ResultSet对象,对于INSERT,UPDATE,DELETE等操作,则使用executeUpdate()方法,返回受影响的行数。 -
处理结果集:遍历
ResultSet对象,从中提取查询到的数据。ResultSet提供了类似游标的机制,通过next()方法移动到下一行,并使用getString(),getInt()等方法获取指定列的值。 -
关闭资源:这是一个至关重要的步骤,为了防止资源泄露,必须在
finally块中或使用try-with-resources语句关闭ResultSet,Statement和Connection对象,关闭的顺序与创建的顺序相反。
下面是一个完整的JDBC查询示例,使用了推荐的 try-with-resources 语法来自动管理资源:
String sql = "SELECT id, name, email FROM users WHERE age > ?";
try (Connection conn = DriverManager.getConnection(url, user, password);
PreparedStatement pstmt = conn.prepareStatement(sql)) {
pstmt.setInt(1, 18); // 设置参数,索引从1开始
try (ResultSet rs = pstmt.executeQuery()) {
while (rs.next()) {
int id = rs.getInt("id");
String name = rs.getString("name");
String email = rs.getString("email");
System.out.printf("ID: %d, Name: %s, Email: %s\n", id, name, email);
}
}
} catch (SQLException e) {
e.printStackTrace();
}
PreparedStatement:安全与高效的查询利器
在上面的例子中,我们已经使用了 PreparedStatement,相比于普通的 Statement,它具有两大核心优势:
- 防止SQL注入:SQL注入是一种常见的安全漏洞,攻击者通过在输入中插入恶意SQL代码来篡改原始查询逻辑。
PreparedStatement通过将SQL语句结构和参数数据分离的方式,从根本上杜绝了这种风险,数据库引擎会先编译SQL语句的模板,再将用户输入的参数作为纯文本数据处理,恶意代码不会被解释执行。 - 性能提升:
PreparedStatement的SQL语句在首次执行时会被数据库预编译,当后续执行相同的查询(只是参数不同)时,数据库可以重用已编译的执行计划,省去了解析和编译的开销,从而显著提高性能,尤其是在循环中执行大量相似查询时。
在任何实际项目中,都应始终优先使用 PreparedStatement 来代替 Statement。

拥抱现代:ORM框架的查询之道
虽然JDBC功能强大,但其代码冗长、繁琐,且需要开发者手动管理资源、处理结果集映射,容易出错,为了提高开发效率和代码质量,对象关系映射(ORM)框架应运而生。
ORM框架在Java对象和数据库表之间建立了一个映射关系,允许开发者以面向对象的方式操作数据库,而无需编写繁琐的SQL语句,主流的ORM框架有Hibernate(JPA规范的实现)和MyBatis。
JPA/Hibernate
JPA (Java Persistence API) 是一套Java官方制定的ORM规范,Hibernate是其最成熟的实现,使用JPA,你只需要定义好实体类(Entity),然后通过EntityManager进行操作。
查询通常通过JPQL(Java Persistence Query Language)或Criteria API实现,JPQL是一种面向对象的查询语言,语法类似SQL,但操作的是实体对象和属性,而非数据库表和列。
// 假设User是一个实体类
String jpql = "SELECT u FROM User u WHERE u.age > :age";
TypedQuery<User> query = entityManager.createQuery(jpql, User.class);
query.setParameter("age", 18);
List<User> users = query.getResultList();
for (User user : users) {
System.out.println(user.getName());
}
MyBatis
MyBatis是一个介于原生JDBC和完整ORM框架之间的“半自动化”解决方案,它将SQL语句从Java代码中解耦,存放在独立的XML映射文件或注解中,并提供了强大的结果集映射机制,开发者需要自己编写SQL,但MyBatis会负责参数的设置和结果的封装。
Mapper接口:
public interface UserMapper {
List<User> findUsersOlderThan(int age);
}
XML映射文件:

<mapper namespace="com.example.mapper.UserMapper">
<select id="findUsersOlderThan" resultType="com.example.model.User">
SELECT id, name, email FROM users WHERE age > #{age}
</select>
</mapper>
MyBatis给予开发者对SQL的完全控制权,非常适合需要精细SQL优化的场景。
核心查询方式对比
为了更直观地理解不同方式的优劣,下表对它们进行了对比:
| 特性 | 原生JDBC (Statement) | 原生JDBC (PreparedStatement) | ORM框架 (如Hibernate/MyBatis) |
|---|---|---|---|
| 易用性 | 低 | 中等 | 高 |
| 开发效率 | 低 | 低 | 高 |
| SQL控制力 | 高 | 高 | 中等 (MyBatis高, Hibernate低) |
| 防SQL注入 | 差 (不安全) | 优秀 | 优秀 |
| 性能 | 中等 | 高 (重复查询时) | 中等 (需优化N+1等问题) |
| 代码维护性 | 差 | 差 | 优秀 |
相关问答 (FAQs)
问题1:PreparedStatement真的能完全防止SQL注入吗?为什么?
解答: 是的,在正确使用的前提下,PreparedStatement 能够完全防止SQL注入,其核心原理在于预编译和参数绑定的分离机制,当您创建一个 PreparedStatement 时,您提供的SQL语句模板(包含 占位符)会被数据库管理系统(DBMS)首先进行编译、解析并生成一个执行计划,这个阶段,SQL的结构已经完全确定,随后,当您通过 setXXX() 方法设置参数时,这些参数是作为纯数据发送给DBMS的,DBMS只会将它们填充到执行计划中预留的位置,而永远不会将它们作为SQL指令的一部分进行解析或执行,即使攻击者输入了如 ' OR '1'='1 这样的恶意字符串,它也只会被当作一个普通的字符串值来处理,无法改变原始SQL的查询逻辑,从而从根本上杜绝了SQL注入的风险。
问题2:在项目中,我应该选择JDBC还是MyBatis/Hibernate这样的框架?
解答: 这个选择取决于项目的具体需求、复杂度和团队的技术栈。
- 选择原生JDBC:适用于非常简单的项目、学习目的、或者对性能有极致要求且SQL逻辑极其特殊的场景,但需要注意,其代码冗长、易于出错,在现代企业级应用中已很少直接作为主要数据访问层。
- 选择MyBatis:当您希望完全掌控SQL语句,但又想摆脱JDBC繁琐的资源管理和结果集映射工作时,MyBatis是理想选择,它非常适合数据库设计复杂、历史包袱重,或者需要对SQL进行深度优化的项目,它在SQL的灵活性和开发的便利性之间取得了很好的平衡。
- 选择Hibernate/JPA:当您追求快速开发和高度的面向对象编程时,JPA/Hibernate是首选,它能让您更专注于业务逻辑而非SQL细节,大大提升了开发效率,特别适合于以领域模型驱动设计(DDD)的项目,但其缺点是,如果对内部机制不熟悉,可能会产生性能问题(如N+1查询),且在处理复杂报表查询时,不如MyBatis灵活。
对于大多数新项目,ORM框架是更现代、更高效的选择,在MyBatis和Hibernate之间,则取决于您对SQL控制权的需求程度。