一.概述

  • Spring Data作为SpringSource的其中一个子项目,旨在统一和简化对各类型持久化存储和访问,支持关系型数据库和非关系型数据库,使开发人员对数据库的访问更方便和快捷。

  • Spring Data主要应用场景

    • Spring Data JPA(重点学习)
    • Spring Data Mongo DB
    • Spring Data Redis
    • Spring Data Solr

二.Spring Data JPA介绍

2.1 Repository接口简介

  • 是Spring Data的核心接口,不提供任何方法

  • public interface Repository <T, ID extends Serializable> { } // T为实体类

    1
    2
    3
    4
    1)Repository是一个空接口,标记接口
    没有包含方法

    2)若接口没有extends Repository则会报错
  • @RepositoryDefinition注解

    1
    2
    3
    <!--添加注解达到extends Repository的功能-->
    @RepositoryDefinition(domainClass = 实体类文件名(不要忘记后缀.class), idClass = Integer.class)
    <!--idClass中的Integer为主键类型,按照实际情况修改-->
  • Repository子接口

    接口 描述
    CrudRepository 继承Repository,实现CRUD相关方法
    PagingAndSortingRepository 继承CrudRepository,实现分页排序相关方法
    JpaRepository 继承上述接口,实现 JPA规范相关方法

2.2 Repository中查询方法定义规则和使用

  • 了解Spring Data中查询方法名称的定义规则

  • 使用Spring Data完成复杂查询方法名称命名

    Repository命名规范

    缺点:1.方法名较长 2.对于复杂的查询难以实现

2.3 Query注解使用

  • 在Repository方法中使用,不需要遵循查询方法命名规则

  • 将@Query加在在Repository中的方法上面

  • 命名参数及索引参数的使用

  • 本地查询

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    // 用自定义的命名规则查最大id用户
    @Query("select o from Users o where id=(select max(id) from Users tb_name)")
    public Users getUserById();

    // 查询特定名字和年龄的用户(方法1)
    @Query("select o from Users o where o.name=?1 and o.age=?2")
    public List<Users> query1(String name, Integer age);

    // 查询特定名字和年龄的用户(方法2)
    @Query("select o from Users o where o.name=:name and o.age=:age")
    public List<Users> query2(@Param("name")String name,@Param("age") Integer age);

    // 模糊查询用户名(方法1)
    @Query("select o from Users o where o.name like %?1%")
    public List<Users> queryLike1(String name);

    // 模糊查询用户名(方法2)
    @Query("select o from Users o where o.name like %:name%")
    public List<Users> queryLike2(@Param("name")String name);

    // 查询总数
    @Query(nativeQuery = true, value="select count(*) from Users")
    public long getCount();

    // 联合查询
    @Query(nativeQuery = true, value = "SELECT a.dep_name " +
    "from department a " +
    "left join job b on b.dep_id = a.dep_id " +
    "where b.jid = ?1")
    String getDeptNameByJobId(Long jid);

2.4 更新及删除操作整合事务的使用

  • 事务在Spring Data中使用

    1
    2
    3
    1)事务一般在Service层
    2)@Query @Modifying @Transactional综合使用
    3)若不使用事务将无法update或delete(报错)
  • @Modifying结合@Query注解执行更新操作

    Service层:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    @Service
    public class Service{

    @Autowired
    private Repository repository;

    @Transactional
    public void update(Integer id, Integer age){
    repository.update(id,age);
    }
    }

    repository:

    1
    2
    3
    @Modifying
    Query("update Users o set o.age=:age where o.id=:id")
    public void update(@Param("id")Integer id, @Param("age")Integer age);

三.Spring Data JPA进阶

3.1 CrudRepository接口的使用

  • extends CrudRepository<实体类名, 主键类型>
  • 提供基本增删改查操作

3.2 PagingAndSortingRepository接口的使用

  • 该接口包含分页和排序功能

  • 带排序的分页查询:findAll(Pageable pageable)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    /**代码举例,假设数据库中有100条数据*/

    // 注意:此处Pageable在org.springframework.data.domain中
    Pageable pageable = new PageRequest(0,5);

    // 取第0页(传入的index值为0开始),每页5条记录
    Page<Users> page = repository.findAll(pageable);

    System.out.println("查询的总页数:" + page.getTotalPages());
    System.out.println("查询的总记录数:" + page.getTotalElements());
    System.out.println("查询的当前为第几页:" + page.getNumber() +1 );
    System.out.println("查询的当前页面对象集合:" + page.getContent());
    System.out.println("查询的当前页面记录数:" + page.getNumberOfElements());

    输出结果:

    1
    2
    3
    4
    5
    查询的总页数:20         // 解析:100条数据分每页5条,一共20页
    查询的总记录数:100
    查询的当前为第几页:1 // 解析:与传入的page值有关
    // 此处输出语句为该页对象的集合
    查询的当前页面记录数:5
  • 排序查询:findAll(Sort sort)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    /**代码举例,假设数据库中有100条数据*/

    // id降序排列
    Sort.Order order1 = new Sort.Order(Sort.Direction.DESC, "id");

    // id升序排列
    Sort.Order order2 = new Sort.Order(Sort.Direction.ASC, "id");

    // 传入Order,关系型数据
    Sort sort = new Sort(order1);

    // Pageable为一个接口,PageRequest是其一个实现类
    Pageable pageable = new PageRequest(0,5,sort);

3.3 JpaRepository接口的使用

  • 常用方法

    常用方法
    findAll
    findAll(Sort sort)
    save(entities)
    flush
    deleteInBatch(entities)
  • 代码举例

    1
    2
    3
    Users user = repository.findOne(1);    // 传入id

    System.out.println("userId=5是否存在:" + repository.exists(5)); // 判断id是否存在

3.4 JpaSpecificationExecutor接口的使用

  • Specification封装了JPA Criteria查询条件

  • extends JpaSpecificationExecutor<T>

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    /**代码举例*/

    /**
    * root:查询类型(实体类)
    * criteriaQuery:查询条件
    * criteriaBuilder:构建Predicate
    * */

    // 查询条件:age<18
    Specification<Users> specification = new Specification<Users>() {
    @Override
    public Predicate toPredicate(Root<Users> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
    // path: root (Users(age))
    Path path = root.get("age");
    return criteriaBuilder.lt(path, 18); // less than 18岁
    }

    Pageable pageable = new PageRequest(0,5);
    // 根据搜查条件并结合分页功能
    Page<Users> page = repository.findAll(specification,pageable);
    };