SpringDataJPA 快速入门

1.1 简介

1.1.1 概述

  Spring Data JPA 是 Spring 基于 ORM 框架、JPA 规范的基础上封装的一套 JPA 应用框架,可使开发者用极简的代码即可实现对数据库的访问和操作。它提供了包括增删改查等在内的常用功能,且易于扩展!学习并使用 Spring Data JPA 可以极大提高开发效率!Spring Data JPA 让我们解脱了 DAO 层的操作,基本上所有 CRUD 都可以依赖于它来实现,在实际的工作工程中,推荐使用 Spring Data JPA + ORM(如:hibernate) 完成操作,这样在切换不同的 ORM 框架时提供了极大的方便,同时也使数据库层操作更加简单,方便解耦

在这里插入图片描述


1.1.2 SpringDataJPA 与 JPA 和 hibernate 之间的关系

  JPA 是一套规范,内部是有接口和抽象类组成的。hibernate 是一套成熟的 ORM 框架,而且 Hibernate 实现了 JPA 规范,所以也可以称 hibernate 为 JPA 的一种实现方式,我们使用 JPA 的 API 编程,意味着站在更高的角度上看待问题(面向接口编程)。SpringDataJPA是 Spring 提供的一套对 JPA 操作更加高级的封装,是在 JPA 规范下的专门用来进行数据持久化的解决方案。

在这里插入图片描述


1.1.3 整合 SpringDataJPA

☞ SpringBoot 整合 SpringDataJPA
☞ Spring 整合 SpringDataJPA





1.2 SpringDataJPA 的使用

1.2.1 使用接中口定义的方法

  SpringDataJPA 致力于减少数据访问层的开发量,开发者唯一要做的就是声明持久层的接口,其他都交给SpringDataJPA来帮你完成。一般我们会继承 JpaRepository 和 JpaSpecificationExecutor 接口,我们可以使用接口中定义的方法进行查询。
  ♞ CrudRepository: 继承 Repository,实现了一组 CRUD 相关的方法
  ♞ PagingAndSortingRepository: 继承 CrudRepository,实现了一组分页排序相关的方法
  ♞ JpaRepository: 继承 PagingAndSortingRepository,实现一组 JPA 规范相关的方法,我们一般继承这个。
  ♞ JpaSpecificationExecutor: 不属于 Repository 体系,实现一组 JPA Criteria 查询相关的方法

在这里插入图片描述


☞ JpaRepository 中定义的方法
在这里插入图片描述

☞ JpaSpecificationExecutor 中定义的方法
在这里插入图片描述


☞ 接口方法速查
在这里插入图片描述


1.2.2 使用 JPQL

  使用 SpringDataJPA 提供的查询方法已经可以解决大部分的应用场景,但是对于某些业务来说,我们还需要灵活的构造查询条件,这时就可以使用 @Query 注解,结合 JPQL 的语句方式完成查询。@Query 注解的使用非常简单,只需在方法上面标注该注解,同时提供一个 JPQL 查询语句即可。☞ JPQL 详细介绍

/**
 * Created with IntelliJ IDEA.
 *
 * @author Demo_Null
 * @date 2020/7/30
 * @description student repository 接口
 */
public interface StudentRepository extends JpaRepository<Student, Long> {
    @Query("from Student")
    public List<Student> findStudent();
}

  此外,也可以通过使用 @Query 来执行一个更新操作,为此,我们需要在使用 @Query 的同时,用 @Modifying 来将该操作标识为修改查询,这样框架最终会生成一个更新的操作,而非查询。可以通过自定义的 JPQL 完成 UPDATE 和 DELETE 操作,注意:JPQL 不支持使用 INSERT 操作。方法的返回值是 int,表示更新语句所影响的行数。默认情况下,SpringDataJPA 的每个方法上有事务, 但都是一个只读事务,他们不能完成修改操作,因此需要在调用的地方必须加事务(添加 @Transactional 注解),没有事务不能正常执行。

/**
 * Created with IntelliJ IDEA.
 *
 * @author Demo_Null
 * @date 2020/7/30
 * @description student repository 接口
 */
public interface StudentRepository extends JpaRepository<Student, Long> {
	//**************************************************************************************
	// 第一种写法
	//**************************************************************************************
    @Modifying
    // ? 后的数字表示第几个参数,顺序与参数一致可不写
    @Query("update Student set sex = ?1, Name = ?2 where id = ?3") 
    public int updateStudent(Boolean sex, String Name, Long id);

	//**************************************************************************************
	// 第二种写法
	//**************************************************************************************
	@Modifying
    @Query("update Student set sex = :sex, Name = :Name where id = :id")
    public int updateStudent(@Param("sex") Boolean sex, @Param("Name") String Name, @Param("id") Long id);
}

1.2.3 使用 SQL 语句

/**
 * Created with IntelliJ IDEA.
 *
 * @author Demo_Null
 * @date 2020/7/30
 * @description student repository 接口
 */
public interface StudentRepository extends JpaRepository<Student, Long> {
	// nativeQuery true: 使用 sql 查询; false: 使用 jpql 查询,默认就是 false
	// 占位符与参数位置对应可不写 ? 后的数字
    @Query(value = "select * from student where id = ?1 or sex = ?2", nativeQuery=true)
    public List<Student> updateStudent(Long id, Boolean sex);
}

1.2.4 方法命名规则查询

  顾名思义,方法命名规则查询就是根据方法的名字,就能创建查询。只需要按照 SpringDataJPA 提供的方法命名规则定义方法的名称,就可以完成查询工作。SpringDataJPA 在程序执行的时候会根据方法名称进行解析,并自动生成查询语句进行查询。按照 SpringDataJPA 定义的规则,查询方法以 findBy 开头,涉及条件查询时,条件的属性用条件关键字连接,要注意的是:条件属性首字母需大写。框架在进行方法名解析时,会先把方法名多余的前缀截取掉,然后对剩下部分进行解析。

☞ 支持的查询关键字

关键字示例JPQL语句
ANDfindByLastnameAndFirstnamewhere x.lastname = ?1 and x.firstname = ?2
OrfindByLastnameOrFirstnamewhere x.lastname = ?1 or x.firstname = ?2
BetweenfindByStartDateBetweenwhere x.startDate between ?1 and ?2
LessThanfindByAgeLessThanwhere x.age < ?1
GreaterThanfindByAgeGreaterThanwhere x.age > ?1
AfterfindByStartDateAfterwhere x.startDate > ?1
BeforefindByStartDateBeforewhere x.startDate < ?1
IsNullfindByAgeIsNullwhere x.age is null
IsNotNull,NotNullfindByAge(Is)NotNullwhere x.age not null
LikefindByFirstnameLikewhere x.firstname like ?1
NotLikefindByFirstnameNotLikewhere x.firstname not like ?1
StartingWithfindByFirstnameStartingWithwhere x.firstname like ?1(parameter bound with appended %)
EndingWithfindByFirstnameEndingWithwhere x.firstname like ?1(parameter bound with prepended %)
ContainingfindByFirstnameContainingwhere x.firstname like ?1(parameter bound wrapped in %)
OrderByfindByAgeOrderByLastnameDescwhere x.age = ?1 order by x.lastname desc
NotfindByLastnameNotwhere x.lastname <> ?1
InfindByAgeIn(Collection ages)where x.age in ?1
NotInfindByAgeNotIn(Collection age)where x.age not in ?1
TruefindByActiveTrue()where x.active = true
FalsefindByActiveFalse()where x.active = false
IgnoreCasefindByFirstnameIgnoreCasewhere UPPER(x.firstame) = UPPER(?1)

☞ 示例

/**
 * Created with IntelliJ IDEA.
 *
 * @author Demo_Null
 * @date 2020/7/30
 * @description student repository 接口
 */
public interface StudentRepository extends JpaRepository<Student, Long> {
    public List<Student> findByAge(int age);
}

☞ 查询方法流程解析

  假如创建如下的查询:findByClassUserAge(),框架在解析该方法时,首先剔除 findBy,然后对剩下的属性进行解析,假设查询实体为 Student,先判断 ClassUserAge(根据 POJO 规范,首字母变为小写)是否为查询实体的一个属性,如果是,则表示根据该属性进行查询;如果没有该属性则从右往左截取第一个大写字母开头的字符串(此处为Age),然后检查剩下的字符串(classUser)是否为查询实体的一个属性,如果是,则表示根据该属性进行查询;如果没有该属性,则继续从右往左截取;假设 class 为查询实体的一个属性,则先判断 class 是否有 userAge 属性,有则按照 Student.class.userAge 查询,没有就会报错。
  可能会存在一种特殊情况,比如 Student 包含一个 class 的属性,也有一个 classUser 属性,此时会存在混淆。可以明确在属性之间加上 _ 以显式表达意图,比如 findByClass_UserAge() 或者 findByClassUser_Age。还有使用一些特殊的参数来完成某些操作,比如说分页操作:Page<UserModel> findByName(String name, Pageable pageable);排序操作:List<UserModel> findByName(String name, Sort sort)

1.2.5 Specifications 动态查询

  有时我们在查询某个实体的时候,给定的条件是不固定的,这时就需要动态构建相应的查询语句,在 SpringDataJPA 中可以通过 JpaSpecificationExecutor 接口查询。相比 JPQL 其优势是类型安全,更加的面向对象。 JpaSpecificationExecutor 这个接口基本是围绕着 Specification 接口来定义的。我们可以简单的理解为,Specification 构造的就是查询条件。Specification 接口中只定义了如下一个方法:public Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder cb); 参数说明:
 ♞ root:Root 接口,代表查询的根对象,可以通过 root 获取实体中的属性;
 ♞ query:代表一个顶层查询对象,用来自定义查询;
 ♞ cb:用来构建查询,此对象里有很多条件方法。
我们写的 Repository 接口需要继承 JpaSpecificationExecutor 之后才能进行动态查询,如下所示:

/**
 * Created with IntelliJ IDEA.
 *
 * @author Demo_Null
 * @date 2020/7/30
 * @description student repository 接口
 */
public interface StudentRepository extends JpaRepository<Student, Long>, JpaSpecificationExecutor<Student> {}

☞ 基于 Specifications 完成条件查询

/**
 * Created with IntelliJ IDEA.
 *
 * @author Demo_Null
 * @date 2020/7/30
 * @description 测试类
 */
@RunWith(SpringRunner.class)
@SpringBootTest()
public class Demo {
    @Autowired
    private StudentRepository studentRepository;

    @Test
    public void test() {
        // 使用匿名内部类的方式,创建一个 Specification 的实现类,并实现 toPredicate 方法
        Specification<Student> spec = new Specification<Student>() {
            public Predicate toPredicate(Root<Student> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
                // cb: 构建查询,添加查询方式   like:模糊匹配
                // root:从实体 Student 对象中按照 Name 属性进行查询
                return cb.like(root.get("Name").as(String.class), "张");
            }
        };
        List<Student> one = studentRepository.findAll(spec);
        System.out.println(one);
    }
}

☞ 基于 Specifications 的分页查询

  对于 SpringDataJPA 中的分页查询,是其内部自动实现的封装过程,返回的是一个 SpringDataJPA 提供的 pageBean 对象。其中的方法有 int getTotalPages():获取总页数;long getTotalElements():获取总记录数;List<T> getContent():获取列表数据

/**
 * Created with IntelliJ IDEA.
 *
 * @author Demo_Null
 * @date 2020/7/30
 * @description 测试类
 */
@RunWith(SpringRunner.class)
@SpringBootTest()
public class Demo {
    @Autowired
    private StudentRepository studentRepository;

    @Test
    public void test() {

        // PageRequest 实现了 Pageable接口,调用静态方法 of 第一个参数:页码(从0开始); 第二个参数:每页查询条数
        Pageable pageable = PageRequest.of(0, 1);

        // 分页查询
        Page<Student> page = studentRepository.findAll(pageable);

        System.out.println(page.getContent());
    }
}

☞ CriteriaBuilder 方法对应关系

方法名称SQL 对应关系
equlefiled = value
gt(greaterThan)filed > value
lt(lessThan)filed < value
ge(greaterThanOrEqualTo )filed >= value
le(lessThanOrEqualTo)filed <= value
notEqulefiled != value
likefiled like value
notLikefiled not like value



  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值