Spring Data JPA详解一、知识概述Spring Data JPA 是 Spring Data 家族的重要组成部分,它基于 JPA(Java Persistence API)规范,通过极其简化的编程模型,大大减少了数据访问层的样板代码。Spring Data JPA 的核心理念是"Repository 抽象",开发者只需定义接口,框架自动提供实现,实现"零代码"数据访问。本文将深入讲解 Spring Data JPA 的核心概念、实体映射、Repository 接口、JPQL 查询、Specification 动态查询等内容,帮助你掌握这个强大的 ORM 框架。二、快速入门2.1 引入依赖!-- Spring Boot 项目引入 Spring Data JPA --dependencies!-- Spring Data JPA --dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-data-jpa/artifactId/dependency!-- 数据库驱动 --dependencygroupIdmysql/groupIdartifactIdmysql-connector-java/artifactIdversion8.0.33/version/dependency!-- Lombok --dependencygroupIdorg.projectlombok/groupIdartifactIdlombok/artifactIdoptionaltrue/optional/dependency/dependencies2.2 配置文件# application.ymlspring:datasource:driver-class-name:com.mysql.cj.jdbc.Driverurl:jdbc:mysql://localhost:3306/jpa_demo?useUnicode=truecharacterEncoding=utf-8serverTimezone=Asia/Shanghaiusername:rootpassword:123456# HikariCP 连接池配置hikari:minimum-idle:5maximum-pool-size:20idle-timeout:30000max-lifetime:120000connection-timeout:30000# JPA 配置jpa:# 数据库类型database:mysql# 显示 SQLshow-sql:true# 格式化 SQLproperties:hibernate:format_sql:true# 二级缓存cache:use_second_level_cache:false# 统计信息generate_statistics:true# DDL 自动生成策略hibernate:ddl-auto:update# 可选值:# - none: 不做任何操作# - validate: 验证表结构,不匹配则报错# - update: 更新表结构(不会删除已存在的列)# - create: 每次启动创建表(会删除旧表)# - create-drop: 启动创建,关闭删除# Open Session In View(生产环境建议关闭)open-in-view:false2.3 快速使用/** * Spring Data JPA 快速入门 */@SpringBootApplication@EnableJpaRepositories(basePackages="com.example.repository")publicclassJpaApplication{publicstaticvoidmain(String[]args){SpringApplication.run(JpaApplication.class,args);}}/** * 实体类 */@Entity@Table(name="sys_user")@DatapublicclassUser{@Id@GeneratedValue(strategy=GenerationType.IDENTITY)privateLongid;@Column(name="username",length=50,nullable=false,unique=true)privateStringusername;@Column(name="email",length=100)privateStringemail;@Column(name="age")privateIntegerage;@Enumerated(EnumType.STRING)@Column(name="status",length=20)privateUserStatusstatus=UserStatus.ACTIVE;@Column(name="create_time",updatable=false)privateLocalDateTimecreateTime;@Column(name="update_time")privateLocalDateTimeupdateTime;// 生命周期回调@PrePersistpublicvoidprePersist(){this.createTime=LocalDateTime.now();this.updateTime=LocalDateTime.now();}@PreUpdatepublicvoidpreUpdate(){this.updateTime=LocalDateTime.now();}}/** * 用户状态枚举 */publicenumUserStatus{ACTIVE,INACTIVE,DELETED}/** * Repository 接口 - 继承 JpaRepository 即可获得 CRUD 能力 */publicinterfaceUserRepositoryextendsJpaRepositoryUser,Long{// JpaRepository 已提供:// - save(S entity) / saveAll(IterableS entities)// - findById(ID id) / findAll() / findAllById(IterableID ids)// - count() / existsById(ID id)// - deleteById(ID id) / delete(T entity) / deleteAll()// - findAll(Sort sort) / findAll(Pageable pageable)// 自定义查询方法UserfindByUsername(Stringusername);ListUserfindByStatus(UserStatusstatus);ListUserfindByAgeBetween(Integermin,Integermax);@Query("SELECT u FROM User u WHERE u.email LIKE %:domain")ListUserfindByEmailDomain(@Param("domain")Stringdomain);}/** * Service 层 */@Service@TransactionalpublicclassUserService{@AutowiredprivateUserRepositoryuserRepository;publicUsercreate(Useruser){returnuserRepository.save(user);}publicUserupdate(Useruser){returnuserRepository.save(user);}publicvoiddelete(Longid){userRepository.deleteById(id);}publicUsergetById(Longid){returnuserRepository.findById(id).orElseThrow(()-newEntityNotFoundException("User not found"));}publicListUserlistAll(){returnuserRepository.findAll();}publicPageUserlistPage(intpage,intsize){returnuserRepository.findAll(PageRequest.of(page,size));}}/** * 测试使用 */@SpringBootTestpublicclassQuickStartTest{@AutowiredprivateUserRepositoryuserRepository;@TestpublicvoidtestInsert(){Useruser=newUser();user.setUsername("zhangsan");user.setEmail("zhangsan@example.com");user.setAge(25);user.setStatus(UserStatus.ACTIVE);Usersaved=userRepository.save(user);System.out.println("保存成功: "+saved);}@TestpublicvoidtestSelect(){// 根据 ID 查询OptionalUseroptional=userRepository.findById(1L);optional.ifPresent(System.out::println);// 查询所有ListUserusers=userRepository.findAll();users.forEach(System.out::println);// 分页查询PageUserpage=userRepository.findAll(PageRequest.of(0,10));System.out.println("总记录数: "+page.getTotalElements());System.out.println("总页数: "+page.getTotalPages());System.out.println("当前页数据: "+page.getContent());}@TestpublicvoidtestUpdate(){Useruser=userRepository.findById(1L).orElse(null);if(user!=null){user.setAge(26);userRepository.save(user);}}@TestpublicvoidtestDelete(){userRepository.deleteById(1L);}}三、实体映射详解3.1 基础注解/** * JPA 实体映射基础注解 */@Entity@Table(name="sys_user",schema="mydb",indexes={@Index(name="idx_username",columnList="username",unique=true),@Index(name="idx_create_time",columnList="create_time")},uniqueConstraints={@UniqueConstraint(name="uk_email",columnNames={"email"})})@DatapublicclassUser{/** * @Id - 主键 * @GeneratedValue - 主键生成策略 */@Id@GeneratedValue(strategy=GenerationType.IDENTITY)// GenerationType 可选值:// - IDENTITY: 数据库自增(MySQL)// - SEQUENCE: 序列(Oracle)// - TABLE: 使用单独的表生成主键// - AUTO: JPA 自动选择(默认)privateLongid;/** * @Column - 字段映射 */@Column(name="username",// 数据库列名length=50,// 长度nullable=false,// 是否允许 nullunique=true,// 是否唯一insertable=true,// 是否参与 insertupdatable=true,// 是否参与 updatecolumnDefinition="VARCHAR(50) COMMENT '用户名'")// DDL 定义privateStringusername;/** * @Enumerated - 枚举映射 */@Enumerated(EnumType.STRING)// 存储枚举名称// EnumType.ORDINAL: 存储枚举序号(默认,不推荐)// EnumType.STRING: 存储枚举名称@Column(name="status")privateUserStatusstatus;/** * @Temporal - 日期时间映射 */@Temporal(TemporalType.TIMESTAMP)// TemporalType.DATE: 只存日期// TemporalType.TIME: 只存时间// TemporalType.TIMESTAMP: 日期时间@Column(name="create_time")privateDatecreateTime;/** * @Lob - 大对象 */@Lob@Column(name="avatar",columnDefinition="LONGBLOB")privatebyte[]avatar;@Lob@Column(name="description",columnDefinition="LONGTEXT")privateStringdescription;/** * @Transient - 忽略映射 */@TransientprivateStringextraField;/** * @Basic - 基本配置 */@Basic(fetch=FetchType.LAZY)// 延迟加载@Column(name="large_content")privateStringlargeContent;}/** * 复合主键 */@Data@EmbeddablepublicclassOrderItemIdimplementsSerializable{@Column(name="order_id")privateLongorderId;@Column(name="product_id")privateLongproductId;}@Entity@Table(name="order_item")@DatapublicclassOrderItem{@EmbeddedIdprivateOrderItemIdid;@Column(name="quantity")privateIntegerquantity;@Column(name="price")privateBigDecimalprice;}// 另一种方式:@IdClass@Entity@Table(name="order_item2")@IdClass(OrderItemId.class)@DatapublicclassOrderItem2{@Id@Column(name="order_id")privateLongorderId;@Id@Column(name="product_id")privateLongproductId;@Column(name="quantity")privateIntegerquantity;}3.2 关联映射/** * 一对一关联 */@Entity@Table(name="user")@DatapublicclassUser{@Id@GeneratedValue(strategy=GenerationType.IDENTITY)privateLongid;private