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 上的课程。
参考课程:
- https://www.imooc.com/learn/821