2018-12-24 · Develop

数据库访问 - Spring Data JPA

Spring Data JPA 是在 JPA 提供的简单语义上做了一定的封装,采用 Hibernate 进行实现,而 Hibernate 实现中有两个特性需要关注:

本文采用的数据库连接等配置和表结构均使用上篇文章 数据库连接 - Spring JDBC Template 的配置和表结构。同时 Spring Boot 支持 JPA 需要引入如下的依赖

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

创建 Entity

JPA 提供丰富的主键来关联实体类和表结构之间的关系:

@Builder
@Entity
@Data
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    @Column
    private String name;
    @Column(name = "department_id")
    private Long departmentId;
    @Column(name = "create_time")
    private Date createTime;
//    @ManyToOne
//    @JoinColumn(name = "department_id")
//    private Department department;
}
@Builder
@Entity
@Data
public class Department {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    @Column
    private String name;
//    @OneToMany(mappedBy = "department")
//    private Set<User> users = new HashSet<>();
}

Repository

Repository 是 Spring Data 的核心概念,抽象了对数据库的各种操作,比较常用的接口如下:

public interface UserRepository extends JpaRepository<User, Long> {

}

测试类如下:

@RunWith(SpringRunner.class)
@SpringBootTest
@Transactional
public class UserRepositoryTest {

    @Autowired
    private UserRepository repository;

    @Test
    public void test() {
        // 新增/修改 - 根据有无主键值
        User user = repository.save(
                User.builder()
                        .name("TEST")
                        .createTime(new Date())
                        .departmentId(2L)
                        .build()
        );
        Assert.assertNotNull(user);

        // 分页查询
        List<User> userList = repository.findAll(PageRequest.of(10, 2)).getContent();
        Assert.assertTrue(userList.size() > 0);

        // 排序查询
        userList = repository.findAll(new Sort(Sort.Direction.ASC, "id"));
        Assert.assertTrue(userList.size() > 0);

        // Example 查询
        userList = repository.findAll(
                Example.of(
                        User.builder()
                                .name("TEST")
                                .build()
                )
        );
        Assert.assertTrue(userList.size() > 0);        
    }
}

Spring Data 可以通过具有一定规则的方法名去自动构造一个 JPQL,比如通过名字查询只需要有方法名, JPA 会自动生成相应的查询实现。

public interface UserRepository extends JpaRepository<User, Long> {

    User findByName(String name);
}

准寻的规则大致如下:

当然依靠自动生成并不能完全满足需求,这个时候可以使用 @query 来定制 sql 语句。默认使用 JPQL,当 nativeQuery 属性为 true 时,则使用 sql 语法。

public interface UserRepository extends JpaRepository<User, Long> {

    User findByName(String name);

    @Query(value = "select * from `user` where `id` = :id and `department_id` = :departmentId", nativeQuery = true)
    User findUserByNative(Long id, Long departmentId);
}

通常情况下, JPQL 语句是运行时决定的,如果需要通过不同条件来组合不同的查询语句的时候,就需要通过底层的 EntityManager 来完成查询了。 EntityManager 已被 Spring 所管理,可以直接注入 Spring Bean 中使用。

@Autowired
private EntityManager entityManager;

@Test
public void entityManagerTest() {
    Query query = entityManager.createQuery("select u from User u");
    Assert.assertTrue(query.getResultList().size() > 0);
}