Appearance
Spring Data JPA
什么是Spring Data JPA?
Spring Data JPA是Spring Data家族的一部分,专注于简化JPA (Java Persistence API) 的使用。它通过减少样板代码和提供通用的Repository接口,让开发者能够更专注于业务逻辑而不是数据访问细节。
主要特性
- 简化的Repository模式:提供了一系列Repository接口,自动实现基本的CRUD操作
- 方法名查询:根据方法名自动生成查询逻辑
- 自定义查询:支持@Query注解自定义JPQL或原生SQL查询
- 分页和排序:内置分页和排序支持
- 审计功能:自动管理创建时间、最后修改时间等审计字段
- 动态查询:提供Specification和Example API进行动态查询构建
设置与配置
Maven依赖
xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
基本配置(application.properties)
properties
# 数据源配置
spring.datasource.url=jdbc:mysql://localhost:3306/mydb
spring.datasource.username=root
spring.datasource.password=password
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
# JPA配置
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.format_sql=true
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL8Dialect
Java配置
java
@Configuration
@EnableJpaRepositories(basePackages = "com.example.repository")
@EntityScan(basePackages = "com.example.entity")
public class JpaConfig {
// 可以在这里添加自定义配置
}
实体定义
java
@Entity
@Table(name = "users")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false, length = 100)
private String name;
@Column(unique = true, nullable = false)
private String email;
@CreatedDate
@Column(updatable = false)
private LocalDateTime createdAt;
@LastModifiedDate
private LocalDateTime updatedAt;
// 构造函数、getter和setter方法
}
Repository定义
基本Repository
java
public interface UserRepository extends JpaRepository<User, Long> {
// 不需要添加任何方法就已经包含了基本的CRUD操作
}
自定义查询方法
java
public interface UserRepository extends JpaRepository<User, Long> {
// 方法名查询
User findByEmail(String email);
List<User> findByNameContaining(String name);
// 组合条件查询
List<User> findByNameAndEmail(String name, String email);
List<User> findByCreatedAtBetween(LocalDateTime start, LocalDateTime end);
// 排序
List<User> findByNameOrderByCreatedAtDesc(String name);
// 自定义查询
@Query("SELECT u FROM User u WHERE u.email LIKE %:domain")
List<User> findByEmailDomain(@Param("domain") String domain);
// 原生SQL查询
@Query(value = "SELECT * FROM users WHERE YEAR(created_at) = :year", nativeQuery = true)
List<User> findUsersCreatedInYear(@Param("year") int year);
// 更新查询
@Modifying
@Transactional
@Query("UPDATE User u SET u.name = :name WHERE u.id = :id")
int updateUserName(@Param("id") Long id, @Param("name") String name);
}
分页和排序
java
// Repository方法
Page<User> findByNameContaining(String name, Pageable pageable);
// 使用方式
Pageable pageable = PageRequest.of(0, 10, Sort.by("name").ascending());
Page<User> userPage = userRepository.findByNameContaining("john", pageable);
// 获取结果
List<User> users = userPage.getContent();
long totalElements = userPage.getTotalElements();
int totalPages = userPage.getTotalPages();
使用Specification进行动态查询
java
public List<User> findUsers(String name, String email) {
return userRepository.findAll((Specification<User>) (root, query, criteriaBuilder) -> {
List<Predicate> predicates = new ArrayList<>();
if (name != null) {
predicates.add(criteriaBuilder.like(root.get("name"), "%" + name + "%"));
}
if (email != null) {
predicates.add(criteriaBuilder.equal(root.get("email"), email));
}
return criteriaBuilder.and(predicates.toArray(new Predicate[0]));
});
}
使用QueryByExample
java
User probe = new User();
probe.setName("John");
Example<User> example = Example.of(probe,
ExampleMatcher.matching()
.withIgnoreCase()
.withStringMatcher(ExampleMatcher.StringMatcher.CONTAINING));
List<User> users = userRepository.findAll(example);
审计功能
要启用审计功能,需要:
java
@Configuration
@EnableJpaAuditing
public class AuditConfig {
@Bean
public AuditorAware<String> auditorProvider() {
return () -> Optional.ofNullable(SecurityContextHolder.getContext())
.map(SecurityContext::getAuthentication)
.filter(Authentication::isAuthenticated)
.map(Authentication::getName);
}
}
然后在实体类上使用:
java
@EntityListeners(AuditingEntityListener.class)
@Entity
public class User {
@CreatedDate
private LocalDateTime createdAt;
@LastModifiedDate
private LocalDateTime updatedAt;
@CreatedBy
private String createdBy;
@LastModifiedBy
private String updatedBy;
}
关系映射
一对多关系
java
@Entity
public class Author {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
@OneToMany(mappedBy = "author", cascade = CascadeType.ALL, orphanRemoval = true)
private List<Book> books = new ArrayList<>();
}
@Entity
public class Book {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String title;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "author_id")
private Author author;
}
多对多关系
java
@Entity
public class Student {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
@ManyToMany
@JoinTable(
name = "student_course",
joinColumns = @JoinColumn(name = "student_id"),
inverseJoinColumns = @JoinColumn(name = "course_id")
)
private Set<Course> courses = new HashSet<>();
}
@Entity
public class Course {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
@ManyToMany(mappedBy = "courses")
private Set<Student> students = new HashSet<>();
}
事务管理
Spring Data JPA集成了Spring的事务管理功能:
java
@Service
@Transactional
public class UserService {
private final UserRepository userRepository;
public UserService(UserRepository userRepository) {
this.userRepository = userRepository;
}
public User createUser(User user) {
// 这个方法自动在事务中执行
return userRepository.save(user);
}
@Transactional(readOnly = true)
public List<User> findAllUsers() {
// 只读事务
return userRepository.findAll();
}
// 如果需要更精细的事务控制
@Transactional(timeout = 10, isolation = Isolation.READ_COMMITTED)
public void complexOperation() {
// ...
}
}
常见问题与最佳实践
N+1查询问题:使用JOIN FETCH或EntityGraph来优化
java@EntityGraph(attributePaths = {"books"}) List<Author> findAll();
延迟加载:默认情况下@ManyToOne和@OneToOne是即时加载,@OneToMany和@ManyToMany是延迟加载,可以根据需要调整
乐观锁:使用@Version注解实现乐观锁
二级缓存:配置Hibernate二级缓存提升性能
批量操作:对于大量数据的插入或更新,考虑使用批处理
总结
Spring Data JPA通过提供高级抽象和自动化的Repository实现,极大地简化了数据访问层的开发工作。它不仅减少了样板代码,还提供了强大的查询功能和性能优化选项,适用于各种规模的应用程序。