SpringDataJPA快速入门
前言
之前在学习 SpringBoot 框架的时候,使用到了 SpringData JPA,但是当时只是简单的查询,没有用到稍微复杂的查询。
JPA 的 JPQL 语法规则对于简单的查询实属利器,大大加快了开发速度。不久前,在公司将用户推荐功能单独抽取出为一个独立项目,由于公司一直沿用的底层框架太老,只能使用 JDK1.6,JDK 1.9都出来了,实在不能忍😅,果断引入了 SpringData JPA。
然后最近公司其他同事接手了该项目,但是不太了解 SpringData JPA 的使用,于是有了此文,不会就可以直接让他看本篇博客了哈哈。
环境准备
这里不讲解 SpringData JPA 与框架的整合,只讲解 JPA 语法的使用
Entity 实体类
@Entity // 表示为一个实体类
@Table("employee") // 表名
public class Employee {
@Id //主键标识注解
@GeneratedValue // 主键生成方式
private Integer id;
private String name;
private Integer age;
//Getter/Setter省略
}
Repository 接口
// 继承 JpaRepository 接口,第一个参数为查询的实体类,第二个为实体类的主键数据类型
public interface EmployeeRepository extends JpaRepository<Employee, Integer>{
}
插入测试数据
@Test
public void testAdd() throws Exception {
for (int i = 0; i < 100; i++) {
Employee employee = new Employee();
employee.setAge(i);
employee.setName("test" + i);
employeeRepository.save(employee);
}
}
JPA 查询语法讲解
使用 JPQL 进行查询
// 新增/更新
employeeRepository.save(employee);
// where name = ?1
employeeRepository.findByName("test1")
// where name = ?1 and age = ?2
employeeRepository.findByNameAndAge("test1", 20);
// where age between ?1 and ?2 【包含头尾】
List<Employee> byAgeBetween = employeeRepository.findByAgeBetween(10, 16);
// where age < ?1
List<Employee> list = employeeRepository.findByAgeLessThan(10);
// where age > ?1
List<Employee> list = employeeRepository.findByAgeGreaterThan(90);
// where name is null 【不包含为空字符串的数据】
List<Employee> list = employeeRepository.findByNameIsNull();
// where name like "test9%" 以test9为开头的name
List<Employee> list = employeeRepository.findByNameLike("test9%");
或者
List<Employee> employees = employeeRepository.findByNameStartingWith("test")
// where name like "test_" 以test开头,且后面只模糊匹配一位
List<Employee> list2 = employeeRepository.findByNameLike("test_");
// where name like "%6" 模糊匹配以6结尾的
List<Employee> employees = employeeRepository.findByNameEndingWith(6)
// where name in (?1, ?2)
List<String> names = Arrays.asList("test1", "test2");
List<Employee> employees = employeeRepository.findByNameIn(names);
// where age <> ?1
List<Employee> employees = employeeRepository.findByAgeNot(99);
// where name = ?1 order by age desc
List<Employee> findByNameOrderByAgeDesc(String name);
使用自定义 Sql 以及 原生 Sql 查询
/** EmployeeRepository.java 添加方法 */
// 根据姓名与年龄查找,[通过占位符获取参数值]
@Query("select o from Employee o where name = ?1 and age = ?2")
List<Employee> queryEmployeeByParams(String name, Integer age);
// 根据姓名与年龄查找,[通过命名参数获取参数值],必须使用 @Param 注解
@Query("select o from Employee o where name = :name and age = :age")
List<Employee> queryEmployeeByParams2(@Param("name") String name, @Param("age") Integer age);
// 原生SQL,与上面不同的是,上面使用的是对象名称以及对象属性名称,Native SQL使用数据库表名以及字段名
@Query(nativeQuery = true, value = "select * from employee where name = :name and age = :age")
List<Employee> queryEmployeeByParams3(@Param("name") String name, @Param("age") Integer age);
JPA 更新操作
/** 需要搭配使用 @Query 与 @Modifying 和 @Transactional 注解使用*/
@Modifying
@Query("update Employee o set o.age = ?2 where o.id = ?1")
Integer updateAge(Integer id, Integer age);
在 Service 层调用
@Autowired
private EmployeeRepository employeeRepository;
@Transactional // 必须开启事务
public void update(Integer id, Integer age) {
employeeRepository.save(id, age);
}
分页查询
// EmployeeRepository 接口定义
Page<Employee> findByNameStartingWith(String name, Pageable pageable);
// 测试类 EmployeeRepositoryTest.java
// 普通分页查询
@Test
public void testFindByNameStartingWith() {
// 注意 page 从 0 开始
Pageable request = new PageRequest(0, 10);
Page<Employee> result = employeeRepository.findByNameStartingWith("test", request);
for (Employee employee : result.getContent()) {
System.out.println(employee);
}
}
// 带排序条件的分页查询
@Test
public void testFindByNameStartingWith() {
Sort.Order order = new Sort.Order(Sort.Direction.DESC, "id");
Sort sort = new Sort(order);
Pageable request = new PageRequest(0, 10, sort);
Page<Employee> result = employeeRepository.findByNameStartingWith("test", request);
for (Employee employee : result.getContent()) {
System.out.println(employee);
}
}
动态 SQL 查询
在 Java 开发中,动态 SQL 是必不可少的,JPA 也可以实现,Repository 多继承一个接口 JpaSpecificationExecutor
即可。
// 修改之前的 EmployeeRepository, 使其多继承 JpaSpecificationExecutor 接口
public interface EmployeeRepository extends JpaRepository<Employee, Integer>, JpaSpecificationExecutor<Employee>{
// ......
}
Pageable request = new PageRequest(0, 10);
Specification<Employee> specification = new Specification<Employee>() {
public Predicate toPredicate(Root<Employee> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
Path<Integer> path = root.get("age");
return cb.gt(path, 50);
}
};
Page<Employee> all = employeeRepository.findAll(specification, request);
后记
这里感谢一下慕课网,快速入门多亏了 imooc 上的课程。
参考课程: