JPA 的说明和使用

JPA 的说明和使用

JPA(Java Persistence API)是Java的ORM规范,用面向对象的方式操作数据库,不用写繁琐的SQL。

核心思想:对象即数据

java 复制代码
// 操作对象 = 操作数据库
User user = new User("张三", "zhangsan@email.com");
userRepository.save(user);  // 自动生成 INSERT SQL

List<User> users = userRepository.findByName("张三"); // 自动生成 SELECT SQL

一、JPA详细使用
1.实体类定义

java 复制代码
@Entity
@Table(name = "users")  // 对应数据库表
public class User {

		// 写法一:主键自增
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

		// 写法二:主键uuid
    @Id
    @GeneratedValue(generator = "system-uuid")
    @GenericGenerator(name = "system-uuid", strategy = "uuid")
    @Column(name = "ID", length = 50, nullable = false)
    private String id;
    
    @Column(name = "user_name", length = 50, unique = true, nullable = false)
    private String username;
    
    private String email;
    
    private Integer age;
    
    @Enumerated(EnumType.STRING)  // 枚举存储为字符串
    private UserStatus status;
    
    @CreationTimestamp  // 自动设置创建时间
    private LocalDateTime createTime;
    
    @UpdateTimestamp    // 自动更新修改时间
    private LocalDateTime updateTime;
    
    // 必须有无参构造器
    public User() {}
    
    // 有参构造器
    public User(String username, String email) {
        this.username = username;
        this.email = email;
    }
    
    // getter/setter 省略...
}

enum UserStatus {
    ACTIVE, INACTIVE, DELETED
}

2.关联关系配置

java 复制代码
// 一对多关系
@Entity
public class User {
    @Id
    private Long id;
    
    // 一个用户有多个订单
    @OneToMany(mappedBy = "user", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
    private List<Order> orders = new ArrayList<>();
}

@Entity
public class Order {
    @Id
    private Long id;
    
    // 多个订单属于一个用户
    @ManyToOne
    @JoinColumn(name = "user_id")  // 外键
    private User user;
    
    private BigDecimal amount;
}

二、JPA常用方法大全
1.基础CRUD方法

java 复制代码
public interface UserRepository extends JpaRepository<User, Long> {
    
    // === 增删改 ===
    // 保存(新增或更新)
    User save(User user);
    List<User> saveAll(List<User> users);
    
    // 删除
    void delete(User user);
    void deleteById(Long id);
    void deleteAll();
    void deleteAll(List<User> users);
    
    // === 查询 ===
    // 根据ID查询
    Optional<User> findById(Long id);
    boolean existsById(Long id);
    
    // 查询所有
    List<User> findAll();
    List<User> findAllById(List<Long> ids);
    
    // 计数
    long count();
}

2.方法名派生查询(最强大!)

java 复制代码
public interface UserRepository extends JpaRepository<User, Long> {
    
    // === 基本查询 ===
    List<User> findByUsername(String username);
    User findFirstByUsername(String username);  // 查询第一条
    Optional<User> findOneByUsername(String username);
    
    // === 条件查询 ===
    List<User> findByAgeGreaterThan(Integer age);           // 大于
    List<User> findByAgeLessThanEqual(Integer age);         // 小于等于
    List<User> findByAgeBetween(Integer start, Integer end); // 区间
    List<User> findByUsernameLike(String pattern);          // 模糊查询
    List<User> findByEmailContaining(String keyword);       // 包含
    List<User> findByUsernameStartingWith(String prefix);   // 开头匹配
    List<User> findByUsernameEndingWith(String suffix);     // 结尾匹配
    
    // === 多条件查询 ===
    List<User> findByUsernameAndAge(String username, Integer age);
    List<User> findByUsernameOrEmail(String username, String email);
    List<User> findByAgeGreaterThanAndStatus(Integer age, UserStatus status);
    
    // === 空值检查 ===
    List<User> findByEmailIsNull();
    List<User> findByEmailIsNotNull();
    
    // === IN 查询 ===
    List<User> findByStatusIn(List<UserStatus> statusList);
    List<User> findByAgeIn(Integer[] ages);
    
    // === 排序 ===
    List<User> findByStatusOrderByCreateTimeDesc(UserStatus status);
    List<User> findByAgeGreaterThanOrderByAgeAscCreateTimeDesc(Integer age);
    
    // === 分页 ===
    Page<User> findByStatus(UserStatus status, Pageable pageable);
    Slice<User> findByAgeGreaterThan(Integer age, Pageable pageable);
    
    // === 限制数量 ===
    List<User> findFirst10ByStatus(UserStatus status);
    List<User> findTop5ByAgeGreaterThanOrderByAgeDesc(Integer age);
}

3.自定义查询

java 复制代码
public interface UserRepository extends JpaRepository<User, Long> {
    
    // === @Query 注解查询 ===
    
    // JPQL 查询(面向对象)
    @Query("SELECT u FROM User u WHERE u.age > :age AND u.status = :status")
    List<User> findAdultUsers(@Param("age") Integer age, 
                             @Param("status") UserStatus status);
    
    // 原生 SQL 查询
    @Query(value = "SELECT * FROM users u WHERE u.create_time > :date", 
           nativeQuery = true)
    List<User> findUsersAfterDate(@Param("date") LocalDateTime date);
    
    // 投影查询(只返回部分字段)
    @Query("SELECT u.username, u.email FROM User u WHERE u.status = 'ACTIVE'")
    List<Object[]> findActiveUserInfo();
    
    // DTO 投影查询
    @Query("SELECT new com.example.UserDTO(u.username, u.email) FROM User u")
    List<UserDTO> findUserDTOs();
    
    // === 修改操作 ===
    @Modifying
    @Query("UPDATE User u SET u.status = :status WHERE u.id = :id")
    int updateUserStatus(@Param("id") Long id, @Param("status") UserStatus status);
    
    @Modifying
    @Query("DELETE FROM User u WHERE u.status = :status")
    int deleteByStatus(@Param("status") UserStatus status);
}

4.复杂查询示例

java 复制代码
public interface UserRepository extends JpaRepository<User, Long> {
    
    // 复杂分页查询
    @Query("SELECT u FROM User u WHERE " +
           "(:username IS NULL OR u.username LIKE %:username%) AND " +
           "(:minAge IS NULL OR u.age >= :minAge) AND " +
           "(:maxAge IS NULL OR u.age <= :maxAge)")
    Page<User> searchUsers(@Param("username") String username,
                          @Param("minAge") Integer minAge,
                          @Param("maxAge") Integer maxAge,
                          Pageable pageable);
    
    // 统计查询
    @Query("SELECT COUNT(u) FROM User u WHERE u.status = :status")
    long countByStatus(@Param("status") UserStatus status);
    
    @Query("SELECT u.status, COUNT(u) FROM User u GROUP BY u.status")
    List<Object[]> countUsersByStatus();
}

5.服务层使用实例

java 复制代码
@Service
@Transactional
public class UserService {
    
    @Autowired
    private UserRepository userRepository;
    
    public void demoUsage() {
        // 1. 新增
        User user = new User("李四", "lisi@email.com");
        user.setAge(25);
        userRepository.save(user);
        
        // 2. 查询
        List<User> youngUsers = userRepository.findByAgeLessThanEqual(30);
        Optional<User> userOpt = userRepository.findByUsername("李四");
        
        // 3. 分页查询
        Page<User> userPage = userRepository.findByStatus(
            UserStatus.ACTIVE, 
            PageRequest.of(0, 10, Sort.by("createTime").descending())
        );
        
        // 4. 更新
        user.setEmail("new_email@example.com");
        userRepository.save(user);  // 自动更新
        
        // 5. 删除
        userRepository.delete(user);
    }
}

三、JPA vs Mybatis详细对比
1.开发模式对比

方面 JPA Mybatis
思维模式 面向对象 面向SQL
查询方式 方法名/JPQL XML/注解SQL
数据库变更 影响较小 影响较大
学习曲线 较陡峭 较平缓

2.代码对比实例
JPA方式

java 复制代码
// Repository 接口
List<User> findByAgeBetweenAndStatusOrderByCreateTimeDesc(
    Integer minAge, Integer maxAge, UserStatus status);

// 使用
List<User> users = userRepository.findByAgeBetweenAndStatusOrderByCreateTimeDesc(
    18, 30, UserStatus.ACTIVE);

Mybatis方式

xml 复制代码
<!-- Mapper XML -->
<select id="selectUsersByCondition" resultType="User">
    SELECT * FROM users 
    WHERE age BETWEEN #{minAge} AND #{maxAge} 
      AND status = #{status}
    ORDER BY create_time DESC
</select>
java 复制代码
// Mapper 接口
List<User> selectUsersByCondition(@Param("minAge") Integer minAge,
                                 @Param("maxAge") Integer maxAge,
                                 @Param("status") String status);

3.性能对比

场景 JPA Mybatis
简单CRUD 效率极高 需要写SQL
复杂查询 JPQL可能性能差 SQL可精细优化
关联查询 容易N+1问题 可手动优化JOIN
批量操作 需要配置 直接批量SQL

4.适用场景总结

选择JPA

复制代码
1.业务模型复杂,对象关系多 
2.需要快速开发标准CRUD
3.团队熟悉面向对象设计 
4.可能更换数据库

选择Mybatis

复制代码
1.复杂SQL、存储过程需求多 
2.需要精细控制SQL性能 
3.遗留数据库表结构复杂 
4.团队SQL能力强

四、实际建议
1.新项目推荐

yaml 复制代码
# 微服务架构选择:
用户服务: JPA          # 业务复杂,对象关系多
订单服务: JPA          # 事务要求高
报表服务: MyBatis      # 复杂查询,需要SQL优化

2.混合使用策略

java 复制代码
// JPA 处理标准业务
public interface UserRepository extends JpaRepository<User, Long> {
    // 标准CRUD
}

// MyBatis 处理复杂查询  
public interface UserReportMapper {
    // 复杂报表查询
    List<UserReportDTO> getUserComplexReport(ReportQuery query);
}

总结

JPA核心优势:

复制代码
1.开发效率:方法名即查询,减少80%的SQL编写 
2.维护性:对象变更自动同步到数据库 
3.类型安全:编译时检查,减少运行时错误
4.标准化:代码更规范,易于团队协作

使用建议:

复制代码
1.掌握方法名规则:解决大部分查询需求
2.合理使用关联:避免N+1查询问题 
3.复杂查询用@Query:保持代码清晰 
4.注意事务管理:保证数据一致性
相关推荐
安冬的码畜日常1 天前
【JUnit实战3_31】第十九章:基于 JUnit 5 + Hibernate + Spring 的数据库单元测试
spring·单元测试·jdbc·hibernate·orm·junit5
_pass_6 天前
flask 框架的ORM 学习及应用
学习·flask·orm
拽着尾巴的鱼儿6 天前
fixed-bug:JPA 关联关系的对象序列化循环引用问题
spring·bug·jpa
123461618 天前
互联网大厂Java面试:从Spring Boot到微服务的探索
java·数据库·spring boot·微服务·面试·mybatis·orm
qqxhb14 天前
系统架构设计师备考第55天——数据库设计融合&物联网层次架构&案例分析
数据库·物联网·系统架构·orm·网络层·感知层·平台应用层
薛家明15 天前
easy-query暴打efcore(包括其他所有orm),隐式Group看我如何在子查询做到极致的性能天花板
java·orm·efcore·easy-query·entityframeworkcore·dotnetcore
薛家明22 天前
C#转java的最好利器easy-query就是efcore4j sqlsugar4j freesql4j
java·orm·easy-query·sqlsugar-java
Jabes.yang2 个月前
互联网大厂Java面试:从Spring到Kafka的技术挑战
spring boot·spring cloud·eureka·kafka·mybatis·jpa·java面试
余衫马3 个月前
Mysql 5.7 与 SqlSugar 5.X 整合开发实战
mysql·c#·orm·sqlsugar