JPA 是什么?它与 Hibernate、JDBC 有什么区别
JPA(Java Persistence API)是 Java 的持久化规范,定义了一套用注解和接口把 Java 对象映射到关系数据库的标准,本身不是能直接运行的实现。你写的代码面向 EntityManager、JPQL 和实体注解,运行时由 Hibernate、EclipseLink 这类实现来执行。选它的前提是:业务以对象模型为主、数据库操作以增删改查和关联加载为主;如果查询逻辑高度依赖手写 SQL 或批量数据处理,直接用 JDBC 往往更直接。
JPA 的定位:规范,不是实现
JPA 由 JSR 338 定义,属于 Java EE / Jakarta EE 体系的一部分。它规定的是“接口长什么样、注解怎么用、生命周期如何管理”,不提供具体实现。这意味着:
- 你的代码依赖
jakarta.persistence(旧版本为javax.persistence)包下的接口和注解; - 换实现时,理论上业务代码不需要改,只换依赖和配置;
- 规范不保证所有实现的行为完全一致,复杂查询和性能调优仍会碰到实现差异。
常见实现:
| 实现 | 说明 |
|---|---|
| Hibernate | 最广泛使用的 JPA 实现,也是 Spring Boot 默认的 JPA 提供方 |
| EclipseLink | 参考实现之一,功能覆盖完整 |
| OpenJPA | Apache 项目,使用相对较少 |
Spring Data JPA 不是 JPA 实现,而是构建在 JPA 之上的封装:它通过方法名派生查询、Repository 接口减少样板代码,底层仍然调用某个 JPA 实现(通常是 Hibernate)。
核心概念
- 实体(Entity):用
@Entity标注的 Java 类,对应数据库中的一张表;字段用@Column、@Id等注解映射到列和主键。 - EntityManager:JPA 的核心操作入口,负责
persist、find、merge、remove以及创建查询。它管理实体的生命周期和一级缓存。 - 持久化上下文(Persistence Context):EntityManager 背后的一组受管实体。同一上下文内,同一个主键只会有一个实体实例,这就是一级缓存。
- JPQL:面向实体而非表的查询语言,例如
SELECT u FROM User u WHERE u.age > 18,由实现翻译成具体数据库的 SQL。 - 事务:实体的变更通常在事务提交时同步到数据库,这也是“脏检查”机制生效的时机。
JPA 与 JDBC 的区别
两者不在同一层:JDBC 是 Java 访问数据库的底层 API,JPA 建立在它之上。
| 维度 | JDBC | JPA |
|---|---|---|
| 操作对象 | 表和 SQL | 实体对象和 JPQL |
| 代码量 | 需要手写 SQL、结果集映射 | 注解映射,增删改查由框架生成 |
| 缓存 | 无内置 | 一级缓存,多数实现支持二级缓存 |
| 关联加载 | 手动处理 | 支持懒加载、急加载 |
| 控制粒度 | 完全掌控 SQL | SQL 由实现生成,需调优时介入 |
适合 JDBC 的场景:批量导入导出、复杂报表查询、需要精确控制 SQL 和连接行为的场合。适合 JPA 的场景:领域模型清晰、以对象读写为主、关联关系较多的业务系统。
什么时候用 JPA,什么时候不用
用 JPA 更合适:
- 业务逻辑围绕实体对象展开,增删改查占多数;
- 需要跨数据库移植,不想绑定具体 SQL 方言;
- 希望用缓存、懒加载、级联等机制减少手写代码。
直接用 JDBC 或原生 SQL 更合适:
- 查询复杂、涉及多表聚合和数据库特有语法;
- 大批量数据处理,需要控制批大小和内存占用;
- 对每条 SQL 的执行计划有严格要求。
实践中两者常混用:主体用 JPA,个别复杂查询走原生 SQL 或 JDBC。
性能相关的一点说明
JPA 的性能表现取决于实现、映射方式和查询写法,不能一概而论。常见的影响因素包括 N+1 查询、懒加载触发时机、一级/二级缓存配置、批量写入设置。jpab.org 是一个 JPA 性能基准测试站点,可用于了解不同实现在各类操作上的相对表现;具体结论应以该站点当前的测试方法和数据为准。