Spring Data JPA入门-JPQL和命名查询

JPQL和命名查询

在使用Spring Data JPA的过程中,框架通过解析方法名称的方式生成对应的SQL,确实为我们减少了很多的工作量,但是,也特殊情况,需要我们手写SQL,当然,这里是JPQL(一种面向对象的SQL语法结构)

使用@Query注解创建查询,将该注解贴在dao的方法上,然后提供一个需要的JPQL语句即可,如:

@Query("SELECT p FROM Person p WHERE name LIKE %?1%")
Person findByName(String name);

如果不使用Query注解,那么Spring Data JPA为我们生成的SQL应该是:

Hibernate: select person0_.id as id1_0_, person0_.age as age2_0_, person0_.name as name3_0_ 
            from Person person0_ where person0_.name=?

使用注解之后执行的SQL:

Hibernate: select person0_.id as id1_0_, person0_.age as age2_0_, person0_.name as name3_0_ 
            from Person person0_ where person0_.name like ?

所以,我们可以通过这种方式来自定义需要执行的SQL语句,这样可以让我们开发者更加自如的来完成我们的需求

很多开发者在创建 JPQL 时喜欢使用命名参数来代替位置编号,@Query 也对此提供了支持。JPQL 语句中通过”: 变量”的格式来指定参数,同时在方法的参数前面使用 @Param 将方法参数与 JPQL中的命名参数对应,示例如下:

@Query("SELECT p FROM Person p WHERE name LIKE %:name%")
Person findByName(@Param("name") String name);

此时大家应该会想一个问题,上面我们都在说如何执行查询操作,查询的SQL可以自动生成也可自定义,那么增删改操作的SQL可以吗?也可以自定生成响应的SQL吗?

答案是肯定的,这里,我们需要使用@Modifying注解来标识该方法执行的是更新或者删除操作,如:

@Modifying
@Query("UPDATE Person p SET p.name = :name WHERE p.id = :id")
void updatePersonName(@Param("id") Integer id, @Param("name") String name);

如此这般,框架执行的就不是查询的SQL,而是更新的SQL

通过调用 JPA 命名查询语句创建查询

命名查询是 JPA 提供的一种将查询语句从方法体中独立出来,以供多个方法共用的功能。Spring Data JPA 对命名查询也提供了很好的支持。用户只需要按照 JPA 规范在 orm.xml 文件或者在实体类中使用 @NamedQuery(或 @NamedNativeQuery)定义好查询语句,唯一要做的就是为该语句命名时,需要满足”DomainClass.methodName”的命名规则。假设定义了如下接口:

Person findByName(@Param("name") String name);

同时在实体类中定义JPQL或者SQL

@NamedQuery(name = "Person.findByName", query = "SELECT p FROM Person p WHERE p.name LIKE :name")
public class Person {
}

此时name属性的值需要按照规则定义,Spring Data JPA根据name属性的值找到对应的JPQL语句并执行

Spring Data JPA的查询策略

以上,我们说到了三种执行SQL的方式,

  1. 框架通过解析方法名称,生成对应的SQL语句
  2. 使用@Query声明JPQL,这样就可以执行我们自定义的语句
  3. Spring Data JPA所支持的命名查询

这里我们来看看框架是如何选择使用哪一种的执行查询的方式:

Spring Data JPA 在为接口创建代理对象时,如果发现同时存在多种上述情况可用,它该优先采用哪种策略呢?为此, 提供了 query-lookup-strategy 属性,用以指定查找的顺序。它有如下三个取值:

  1. create —- 通过解析方法名字来创建查询。即使有符合的命名查询,或者方法通过 @Query 指定的查询语句,都将会被忽略。

  2. create-if-not-found —- 如果方法通过 @Query 指定了查询语句,则使用该语句实现查询;如果没有,则查找是否定义了符合条件的命名查询,如果找到,则使用该命名查询;如果两者都没有找到,则通过解析方法名字来创建查询。这是 query-lookup-strategy 属性的默认值。

  3. use-declared-query —- 如果方法通过 @Query 指定了查询语句,则使用该语句实现查询;如果没有,则查找是否定义了符合条件的命名查询,如果找到,则使用该命名查询;如果两者都没有找到,则抛出异常。

为接口中的部分方法提供自定义实现
在实际开发中,我们会遇到一些需要自定义持久层实现的需求,也就是Spring Data JPA的实现不能满足我们的要求,所以Spring Data JPA考虑到了这一点,为我们提供了自定义实现持久层的方式

将需要开发者手动实现的方法从持久层接口(假设为 UserDao )中抽取出来,独立成一个新的接口(假设为 IUserDaoBase ),并让 IUserDao 继承 IUserDaoBase;
为 IUserDaoBase 提供自定义实现(假设为 IUserDaoBaseImpl );
将 IUserDaoBaseImpl 配置为 Spring Bean;
中按下面的方式进行配置。

 
 



此外, 提供了一个 repository-impl-postfix 属性,用以指定实现类的后缀。如:



在框架扫描到 IUserDao 接口时,它将尝试在相同的包目录下查找 IUserDaoImpl.java,如果找到,便将其中的实现方法作为最终生成的代理类中相应方法的实现。

到此,Spring Data JPA的基本使用我们就先到这

你可能感兴趣的:(Spring Data JPA入门-JPQL和命名查询)