你希望深入了解 JPA 这个 ORM 规范,我会从它的定义、核心设计思想、核心组件、常用注解、基本使用方式以及与 Hibernate 的关系等方面,为你做全面且易懂的讲解,帮你彻底搞懂 JPA。
一、JPA 是什么?
JPA(Java Persistence API,Java 持久化 API)不是一个具体的 ORM 框架 ,而是 Java EE 官方制定的一套对象关系映射的标准规范(接口 + 注解/XML)。
简单理解:
- JPA 是"接口/规则",定义了如何将 Java 对象映射到数据库表、如何执行 CRUD 操作等标准;
- Hibernate、EclipseLink、OpenJPA 是 JPA 的实现(具体干活的框架),其中 Hibernate 是最主流、最成熟的实现,也是 Spring Data JPA 默认的底层实现。
JPA 诞生的核心目的:统一 Java 持久层的开发标准,避免开发者被某一个 ORM 框架绑定(比如早期只用 Hibernate 会导致代码和框架强耦合)。
二、JPA 的核心设计思想
JPA 遵循"面向对象"的设计思路,核心是将数据库表与 Java 实体类(Entity)做映射,让你通过操作 Java 对象来完成数据库操作,无需编写原生 SQL(也支持自定义 SQL)。
核心目标:
- 消除 JDBC 代码的冗余(不用手动写
Connection、PreparedStatement、结果集映射等); - 以面向对象的方式操作数据库(比如用
entityManager.persist(user)代替INSERT语句); - 提供统一的 API,降低切换 ORM 实现的成本(比如从 Hibernate 切换到 EclipseLink 只需改配置)。
三、JPA 的核心组件
JPA 的核心由 3 部分组成,也是你使用 JPA 必须掌握的核心内容:
1. 核心 API(接口)
| API 接口 | 作用 |
|---|---|
EntityManager |
JPA 的核心操作接口,用于执行实体的增删改查、获取事务、创建查询等 |
EntityManagerFactory |
用于创建 EntityManager 的工厂类(重量级对象,全局只创建一个) |
EntityTransaction |
事务管理接口(也可结合 Spring 事务使用,更推荐) |
Query/TypedQuery |
JPA 的查询接口,支持 JPQL/SQL 查询 |
2. 注解(核心,用于对象-表映射)
JPA 的核心注解都在 javax.persistence 包下(Spring Boot 中已自动引入),常用注解如下:
| 注解 | 作用 |
|---|---|
@Entity |
标记类为 JPA 实体类,对应数据库中的一张表 |
@Table |
配置实体类对应的数据库表名(默认类名小写) |
@Id |
标记字段为主键 |
@GeneratedValue |
配置主键生成策略(如自增、UUID 等) |
@Column |
配置字段对应的数据库列名、长度、非空、唯一等属性(默认字段名) |
@Transient |
标记字段不映射到数据库(仅内存使用) |
@OneToOne |
一对一关联关系 |
@OneToMany |
一对多关联关系 |
@ManyToOne |
多对一关联关系 |
@ManyToMany |
多对多关联关系 |
3. 查询语言:JPQL
JPQL(Java Persistence Query Language)是 JPA 定义的面向对象的查询语言,基于实体类和属性(而非数据库表和字段),最终会被 JPA 实现(如 Hibernate)翻译成原生 SQL。
比如:
- JPQL:
SELECT u FROM User u WHERE u.userName = ?1(User 是实体类名,userName 是实体属性) - 对应的 SQL:
SELECT * FROM t_user WHERE user_name = ?
JPQL 支持分页、排序、聚合函数(COUNT/SUM 等),也支持原生 SQL 嵌入。
四、JPA 的基本使用(纯 JPA + Spring Boot 两种方式)
方式 1:纯 JPA 原生使用(理解底层原理)
java
// 1. 定义实体类
import javax.persistence.*;
@Entity // 标记为实体类
@Table(name = "t_user") // 对应数据库表 t_user
public class User {
@Id // 主键
@GeneratedValue(strategy = GenerationType.IDENTITY) // 自增主键(MySQL 适用)
private Long id;
@Column(name = "user_name", length = 50, nullable = false, unique = true)
// 映射字段:列名 user_name,长度 50,非空,唯一
private String userName;
@Column(nullable = false) // 非空
private Integer age;
@Transient // 该字段不映射到数据库
private String tempField;
// 必须有无参构造器(JPA 反射需要)
public User() {}
// 有参构造器、getter/setter 省略
}
// 2. 原生 JPA 操作(手动管理 EntityManager)
public class JpaNativeDemo {
public static void main(String[] args) {
// 1. 创建 EntityManagerFactory(全局唯一,重量级)
EntityManagerFactory emf = Persistence.createEntityManagerFactory("jpa_demo");
// 2. 创建 EntityManager(轻量级,每次操作创建/关闭)
EntityManager em = emf.createEntityManager();
// 3. 开启事务
EntityTransaction tx = em.getTransaction();
tx.begin();
try {
// 4. 操作数据库:保存用户
User user = new User();
user.setUserName("张三");
user.setAge(25);
em.persist(user); // 插入数据(对应 INSERT)
// 5. 查询用户
User findUser = em.find(User.class, 1L); // 根据主键查询(对应 SELECT)
System.out.println("查询到用户:" + findUser.getUserName());
// 6. 修改用户
findUser.setAge(26);
em.merge(findUser); // 更新数据(对应 UPDATE)
// 7. 删除用户
// em.remove(findUser); // 删除数据(对应 DELETE)
// 8. 提交事务
tx.commit();
} catch (Exception e) {
// 回滚事务
tx.rollback();
e.printStackTrace();
} finally {
// 关闭资源
em.close();
emf.close();
}
}
}
// 3. 配置文件(META-INF/persistence.xml)
<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
version="2.1">
<persistence-unit name="jpa_demo" transaction-type="RESOURCE_LOCAL">
<!-- JPA 实现类(Hibernate) -->
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
<!-- 映射的实体类 -->
<class>com.example.entity.User</class>
<properties>
<!-- 数据库连接信息 -->
<property name="javax.persistence.jdbc.driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/test?useSSL=false"/>
<property name="javax.persistence.jdbc.user" value="root"/>
<property name="javax.persistence.jdbc.password" value="123456"/>
<!-- Hibernate 配置 -->
<property name="hibernate.hbm2ddl.auto" value="update"/> <!-- 自动更新表结构 -->
<property name="hibernate.show_sql" value="true"/> <!-- 打印 SQL -->
<property name="hibernate.format_sql" value="true"/> <!-- 格式化 SQL -->
<property name="hibernate.dialect" value="org.hibernate.dialect.MySQL8Dialect"/> <!-- 数据库方言 -->
</properties>
</persistence-unit>
</persistence>
方式 2:Spring Boot + Spring Data JPA(实际开发主流)
Spring Data JPA 是 Spring 对 JPA 的进一步封装,提供了通用的 CRUD 接口,无需手动写基础操作代码,是实际开发中最常用的方式:
步骤 1:引入依赖(pom.xml)
xml
<dependencies>
<!-- Spring Boot JPA 起步依赖(自动引入 Hibernate) -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<!-- MySQL 驱动 -->
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>
<!-- Spring Boot Web(方便测试) -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
步骤 2:配置 application.yml
yaml
spring:
# 数据库连接配置
datasource:
url: jdbc:mysql://localhost:3306/test?useSSL=false&serverTimezone=Asia/Shanghai
username: root
password: 123456
driver-class-name: com.mysql.cj.jdbc.Driver
# JPA 配置
jpa:
hibernate:
ddl-auto: update # 表结构策略:none(无)、create(每次创建)、update(更新)、validate(校验)
show-sql: true # 打印 SQL
properties:
hibernate:
format_sql: true # 格式化 SQL
open-in-view: false # 关闭 Open Session In View(避免性能问题)
database-platform: org.hibernate.dialect.MySQL8Dialect # 数据库方言
步骤 3:编写 Repository 接口(核心,无需写实现)
java
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import java.util.List;
// 继承 JpaRepository<实体类, 主键类型>,自动获得 CRUD 方法
public interface UserRepository extends JpaRepository<User, Long> {
// 1. 按方法名自动生成 SQL(无需写 JPQL/SQL)
User findByUserName(String userName); // 根据用户名查询
List<User> findByAgeGreaterThan(Integer age); // 查询年龄大于指定值的用户
// 2. 自定义 JPQL 查询(推荐)
@Query("SELECT u FROM User u WHERE u.age BETWEEN :minAge AND :maxAge")
List<User> findByAgeRange(@Param("minAge") Integer minAge, @Param("maxAge") Integer maxAge);
// 3. 自定义原生 SQL 查询
@Query(value = "SELECT * FROM t_user WHERE age = ?1", nativeQuery = true)
List<User> findByAge(Integer age);
}
步骤 4:编写 Service 和 Controller(测试)
java
// Service 层(整合事务)
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
@Service
public class UserService {
@Autowired
private UserRepository userRepository;
// 保存用户(事务)
@Transactional
public User saveUser(User user) {
return userRepository.save(user); // 内置 save 方法
}
// 根据 ID 查询
public User getUserById(Long id) {
// findById 返回 Optional,避免空指针
return userRepository.findById(id).orElse(null);
}
// 查询所有用户
public List<User> getAllUsers() {
return userRepository.findAll();
}
// 自定义查询:按年龄范围
public List<User> getUsersByAgeRange(Integer min, Integer max) {
return userRepository.findByAgeRange(min, max);
}
// 删除用户
@Transactional
public void deleteUser(Long id) {
userRepository.deleteById(id);
}
}
// Controller 层(测试接口)
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/users")
public class UserController {
@Autowired
private UserService userService;
// 新增用户
@PostMapping
public User addUser(@RequestBody User user) {
return userService.saveUser(user);
}
// 根据 ID 查询
@GetMapping("/{id}")
public User getUser(@PathVariable Long id) {
return userService.getUserById(id);
}
// 查询所有
@GetMapping
public List<User> getAll() {
return userService.getAllUsers();
}
// 按年龄范围查询
@GetMapping("/age-range")
public List<User> getByAgeRange(@RequestParam Integer min, @RequestParam Integer max) {
return userService.getUsersByAgeRange(min, max);
}
// 删除用户
@DeleteMapping("/{id}")
public String delete(@PathVariable Long id) {
userService.deleteUser(id);
return "删除成功";
}
}
五、JPA 的核心优势与适用场景
优势:
- 标准化:遵循 Java 官方规范,不绑定具体实现,可灵活切换 ORM 框架;
- 简化开发:无需写基础 CRUD 代码,Spring Data JPA 按方法名自动生成 SQL;
- 面向对象:以操作 Java 对象的方式操作数据库,符合面向对象编程思想;
- 灵活查询:支持 JPQL、原生 SQL、方法名查询三种方式,兼顾简洁性和灵活性;
- 无缝整合 Spring:与 Spring Boot/Spring 事务/AOP 等生态完美融合。
适用场景:
- 中大型企业级应用,追求代码规范、低耦合;
- 业务逻辑以简单 CRUD 为主,无需复杂 SQL;
- 希望快速开发,减少重复的数据库操作代码;
- 需兼顾跨数据库兼容性(JPA 自动适配不同数据库方言)。
局限性:
- 复杂 SQL(如多表关联、分组聚合、存储过程)不如 MyBatis 灵活;
- 自动生成的 SQL 可能存在性能问题(需手动优化);
- 学习成本略高(需理解 ORM 思想、JPQL、关联关系等)。
总结
- JPA 是ORM 规范,而非具体框架,Hibernate 是其最主流的实现,Spring Data JPA 是 Spring 对 JPA 的进一步封装(开发首选);
- JPA 的核心是通过注解 实现 Java 实体类与数据库表的映射,通过
EntityManager或 Spring Data JPA 接口完成数据库操作; - Spring Boot + Spring Data JPA 是实际开发的主流方式,核心优势是简化 CRUD 开发、统一规范、整合 Spring 生态,适合中大型应用的快速开发。