Spring-data-jpa的使用

524 阅读4分钟

使用方式:

1. 引入依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>

2. 定义实体类

首先,你需要定义一个Java类来表示数据库中的实体。这个类应该使用@Entity注解,并且包含一些其他的JPA注解,如@Id来标识主键字段,@GeneratedValue来指定主键生成策略,以及@Column来指定列的细节。

import javax.persistence.*;

@Entity
@Table(name = "users")
public class User {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(name = "username", nullable = false)
    private String username;

    @Column(name = "password", nullable = false)
    private String password;
    
    // Getter and Setter methods...
}

3. 创建Repository接口

接下来,你需要创建一个接口来继承JpaRepository,这个接口会自动被Spring Data JPA识别并实例化。

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface UserRepository extends JpaRepository<User, Long> {
    // 可以在这里定义额外的查询方法
}

4. 使用Repository

然后,在你的服务层或控制器中注入创建的Repository,你可以通过这个接口调用各种预定义的方法。 预定义方法:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class UserService {

    private final UserRepository userRepository;

    @Autowired
    public UserService(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    public User createUser(User user) {
        return userRepository.save(user);
    }

    public List<User> findAllUsers() {
        return userRepository.findAll();
    }
}

自定义方法:

public interface UserRepository extends JpaRepository<User, Long> {
    List<User> findByUsername(String username);
    List<User> findByUsernameOrEmail(String username, String email);
}

接口介绍:

在Spring Data JPA中,有几个主要的Repository接口,它们形成了层次结构,每个接口都提供了不同级别的功能。以下是一些核心的接口及其功能概述:

1. Repository

  • 这是最基础的接口,提供了非常有限的数据访问能力。

2. CrudRepository

  • 扩展了Repository接口,提供了基本的CRUD(创建、读取、更新、删除)操作。
  • 方法包括:save()findById()findAll()update()deleteById()delete()等。

3. PagingAndSortingRepository

  • 扩展了CrudRepository,增加了分页和排序的功能。
  • 方法包括:findAll(Pageable)用于分页查询,findAll(Sort)用于排序查询。

4. JpaRepository

  • 继承自PagingAndSortingRepository,这是Spring Data JPA中最常用的接口。
  • 它结合了基本的CRUD操作和高级的分页、排序功能。
  • 同时也支持一些数据库特定的操作,如批量插入和更新。 分页和排序使用方式:使用PageableSort进行分页和排序 如果需要同时分页和排序,可以在PageRequest构造函数中同时传入Sort参数。
Pageable pageable = PageRequest.of(pageNumber, pageSize, Sort.by("username").ascending());
Page<User> users = userRepository.findAll(pageable);

5. QueryByExampleExecutor

  • 提供了基于实例查询的能力,允许你使用实体对象作为查询条件。
  • 方法包括:findOne(Example<T>)findAll(Example<T>)count(Example<T>)exists(Example<T>)等。

6. JpaSpecificationExecutor

  • 允许使用Specification接口来构建动态查询。
  • 方法包括:findOne(Specification<T>)findAll(Specification<T>)count(Specification<T>)exists(Specification<T>)等。

当定义你自己的Repository接口时,通常会继承JpaRepository,因为它已经包含了所有常见的数据访问操作,包括基本的CRUD、分页、排序、实例查询和规格化查询。当然,你也可以选择继承更基础的接口,然后自己定义更多特定的查询方法,使用方法命名约定或@Query注解来实现复杂查询。

内部原理

1. Repository 接口

Spring Data JPA 允许开发者定义扩展 JpaRepository 或其子接口如 CrudRepository 的接口,这些接口不需要任何实现代码。当这些接口被 Spring 上下文检测到时,Spring 会自动为它们提供实现

2. 动态代理

当你注入一个 Repository 接口时,Spring 会使用动态代理(通常是 JDK Dynamic ProxyCGLIB)来创建一个代理对象。这个代理对象会在运行时拦截对 Repository 方法的调用,然后将其转换成对底层 EntityManager 的调用

3. 方法命名约定

Spring Data JPA 支持基于方法名的查询派生。例如,一个方法名 findAllByLastName(String lastName) 可以被解释为一个查询,用于查找具有特定姓氏的所有实体。

4. EntityManager

EntityManagerJPA 的核心组件,用于与数据库进行交互。Spring Data JPA 使用 EntityManager 来执行持久化操作,如保存、更新、删除和查询实体

5. 启用 JPA Repositories

要启用 Spring Data JPA,通常需要在配置类上添加 @EnableJpaRepositories 注解。这会告诉 Spring 去扫描指定的包寻找 Repository 接口并为它们创建代理。

6. 查询方法的解析

对于基于方法名的查询,Spring Data JPA 会解析方法签名并构建相应的 JPQL 或 SQL 查询。如果需要更复杂的查询逻辑,还可以使用 @Query 注解来指定自定义的查询语句。

7. 事务管理

所有的 Repository 方法默认都在一个事务内执行。这意味着,如果你在一个 Service 方法中调用了多个 Repository 方法,所有这些调用都将被视为一个单元,只有当所有操作成功完成时,更改才会被提交到数据库。

8. 延迟加载

Spring Data JPA 默认使用延迟加载策略,这意味着关联的对象只在真正需要时才从数据库加载,从而提高了性能和响应速度。