数据访问(二):Spring Data JPA
依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
该 starter 聚合 Spring Data JPA 与默认实现 Hibernate,并自带事务支持;再加数据库驱动即可(同 14 章)。实体注解使用 jakarta.persistence.* 包。
实体
import jakarta.persistence.*;
@Entity
@Table(name = "t_user")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private Integer age;
// 无参构造、getter/setter 省略
}
要点:需要无参构造;@GeneratedValue(strategy = IDENTITY) 表示自增主键;字段名与列名的映射规则(含下划线命名)以官方文档为准。
Repository:接口即实现
public interface UserRepository extends JpaRepository<User, Long> {
// 方法名派生查询
List<User> findByName(String name);
boolean existsByAge(Integer age);
long countByName(String name);
List<User> findByAgeGreaterThanEqualOrderByIdDesc(int age);
}
Spring Data 在启动时为接口生成代理实现,无需写实现类。规则是「动词 + By + 条件属性」,支持 And/Or/GreaterThan/Containing/OrderBy 等连接词;方法名中属性拼写错误会在启动阶段报错。
JpaRepository 自带常用方法:save、findById(返回 Optional)、findAll、deleteById、existsById、count。
分页与排序
Page<User> page = repo.findByAge(18, PageRequest.of(0, 10, Sort.by("id").descending()));
List<User> content = page.getContent();
long total = page.getTotalElements();
分页查询返回 Page<T>,内含数据与总数等信息;PageRequest.of(页码, 每页条数, Sort) 构造分页条件(页码从 0 开始)。
@Query 自定义查询
方法名搞不定时用 @Query 写 JPQL(面向实体):
public interface UserRepository extends JpaRepository<User, Long> {
@Query("select u from User u where u.name like concat('%', :kw, '%')")
List<User> search(@Param("kw") String kw);
@Query(value = "select * from t_user where age > :minAge", nativeQuery = true)
List<User> findByAgeGreaterThan(@Param("minAge") int minAge);
}
nativeQuery = true表示原生 SQL;- 更新/删除类语句还要加
@Modifying,并让调用在事务中执行:
@Modifying
@Query("update User u set u.age = u.age + 1 where u.id = :id")
int increaseAge(@Param("id") Long id);
常用配置
spring.jpa.hibernate.ddl-auto=update # none / validate / update / create
spring.jpa.show-sql=true # 开发期打印 SQL
ddl-auto 由 Hibernate 按实体自动维护表结构:开发期常用 update,生产建议 validate 或 none(由 DBA 管理表结构)。完整属性清单以官方文档为准。
小结
Spring Data JPA 的核心是「实体 + Repository 接口」:简单 CRUD 零实现代码,复杂查询用方法名派生或 @Query。相比 14 章的 JdbcTemplate 它更「对象化」,代价是 SQL 由框架生成、复杂查询调优需要额外手段——这正是 16 章 MyBatis 的用武之地。