Spring Data Jpa 自定义查询定义规则 及事务、分页

关于SpringData JPA查询的定义

  1. spring data 对于定义方法的查询策略

查询策略是spring data 根据方法名称取解析用户的查询意图,

第一种,根据方法的命名规则解析,
第二种是通过Query去解析,

如果两种同时存在时,springdata按照那种解析方法名,这就是spring data的查询策略,查询策略可以在jpa:repositorys/ 属性query-lookup-strategy 配置

CREATE: 通过解析方法的名称来创建查询,也就是下面的规则1

USE_DECLARED_QUERY:根据定义好的语句去查询,如果找不到,抛出异常信息。查询语句定义在某个注解或者方法上。

CREATE_IF_NOT_FOUND:优先查询方法上是否有定义好的查询语句,如果没有,则按照方法名称解析,这是默认的策略。

public interface UserRepository extends JpaRepository<User,Integer>, JpaSpecificationExecutor<User> {
    //根据springData的关键字命名方法名称,可以不用写实现类
    List<User> findByNameAndAge(String name, Integer age);
 
    List<User> findByNameLikeAndAge(String name, Integer age);
    //@Query注解里面写JPQL语句,定义查询
    @Query(nativeQuery = false,value = " SELECT p FROM User p WHERE id = ?1")
    User readId(Integer id);
    //Query注解也可以定义SQL语句,只要将nativeQuery属性改为true
    @Query(nativeQuery = true, value = "select name from user where id = :id")
    String findNamebyId(@Param("id")Integer id);
    //@Modifying修饰方法,告知SpringData,这是一个UPATE或者DELETE操作
    //在service层的方法上添加事务操作
    @Modifying
    @Query(nativeQuery = true,value = "update user set name = ?1  where id = ?2 ")
    int updateUserNameById(String name,Integer id);
 
}

规则1:根据SpringData JPA的关键字定义方法名,方法的参数顺序和关键字的顺序一致,名称可以不一致。

Spring Data JPA对方法名称进行解析的时候,会将一些无用的前缀名自动去除,比如find、findBy、read、readBy,然后根据关键字解析成对应JPQL语句。也要注意方法的参数顺序和定义的关键字的顺序一致。

规则2:定义方法时候,上面加上注解@Query,默认nativeQuery是false,此时value填入的是JPQL语句,修改nativeQuery是true,就能够写入SQL语句

//@Query注解里面写JPQL语句,定义查询
    @Query(nativeQuery = false,value = " SELECT p FROM User p WHERE id = ?1")
    User readId(Integer id);
    //Query注解也可以定义SQL语句,只要将nativeQuery属性改为true
    @Query(nativeQuery = true, value = "select name from user where id = :id")
    String findNamebyId(@Param("id")Integer id);

注意参数注入的方式有两种:

  1. [?][方法参数索引],索引从1开始,例 ?1,?2
    @Query(nativeQuery = false,value = " SELECT p FROM User p WHERE id = ?1")
    User readId(Integer id);
  1. [:][],[...:][参数名],参数名必须是实体的属性名,并且方法参数上加上对应的注解@Param("xxx")@Param('yyy')
    @Query(nativeQuery = true, value = "select name from user where id = :id")
    String findNamebyId(@Param("id")Integer id);

@Modify和事务

可以通过JPQL语句定义update/delete,此时在@Query注解中定义,必须加上@Modify,告诉spring data 这是一个update/delete操作。

update/delete操作需要事务支持,必须在service层,添加事务,因为spring data,默认情况下每个方法是只读事务,不能完成update/delete操作。

public interface UserRepository extends JpaRepository<User,Integer>, JpaSpecificationExecutor<User> {
    //根据springData的关键字命名方法名称,可以不用写实现类
    List<User> findByNameAndAge(String name, Integer age);
    List<User> findByNameLikeAndAge(String name, Integer age);
    //@Query注解里面写JPQL语句,定义查询
    @Query(nativeQuery = false,value = " SELECT p FROM User p WHERE id = ?1")
    User readId(Integer id);
    //Query注解也可以定义SQL语句,只要将nativeQuery属性改为true
    @Query(nativeQuery = true, value = "select name from user where id = :id")
    String findNamebyId(@Param("id")Integer id);
    //@Modifying修饰方法,告知SpringData,这是一个UPATE或者DELETE操作
    //在service层的方法上添加事务操作
    @Modifying
    @Query(nativeQuery = true,value = "update user set name = ?1  where id = ?2 ")
    int updateUserNameById(String name,Integer id);
}
@Service
public class UserServiceImpl implements  UserService {
    @Autowired
    private UserRepository repository;
    //对于SpringData jpa的update或者delete操作,必须在service层使用事务,直接使用仓库的方法会报错
    //另外,SpringData jpa 的 JPQL语法不支持insert
    @Transactional(propagation = Propagation.REQUIRED)
    public int updateUserNameById(String name,Integer id){
        return repository.updateUserNameById(name,id);
    }
 
}
@RunWith(value = SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:applicationContext.xml"})
public class SpringDataTest {
    @Autowired
    private UserRepository repository;
    @Autowired
    private UserService service;
 
    @Test
    public void test(){
        service.updateUserNameById("张三",1);
    }
}

分页和模糊查询

模糊查询

需要注意的是%%外面不需要再加上''

//模糊查询
    @Query(nativeQuery = true,value = " select  * from user where name like %?1% ")
    User findUserByLikeName(String name);

分页对象

  1. 要求自定义的Repository必须继承了PagingAndSortingRepository或者他的子类JpaRepository

  2. 分页对象是Pageable接口的实现类PageRequest

public class PageRequest implements Pageable, Serializable {
    private static final long serialVersionUID = 8280485938848398236L;
    private final int page;//页码,从0开始,0表示第一页,1表示第二页,以此类推
    private final int size;//每页显示的记录数
    private final Sort sort;//排序规则

Sort对象,定义排序规则,常用的是下面这种构造函数,支持可变参数的

public Sort(Sort.Direction direction, String... properties) {
        this(direction, (List)(properties == null ? new ArrayList() : Arrays.asList(properties)));
    }

定义分页查询,只需要将查询的参数和分页对象作为参数。

Page<User> findByNameLike(String str , Pageable pageable);
@RunWith(value = SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:applicationContext.xml"})
public class SpringDataTest {
    @Autowired
    private UserRepository repository;
    @Test
    public void test(){
       /**
        * SpringData jpa 的分页
        * Pageable接口的实现类是PageRequest,Page接口的实现类是PageImpl。
        */
       Pageable page = new PageRequest(0,2,new Sort(Sort.Direction.DESC,"id"));
       Page<User> personList =  repository.findByNameLike("张%",page);
        System.out.println("总记录数" + personList.getTotalElements());
        System.out.println("当前第几页: " + (personList.getNumber() + 1));
        System.out.println("总页数: " + personList.getTotalPages());
        System.out.println("当前页面的记录数:" + personList.getContent());
        System.out.println("当前页面的记录数: " + personList.getNumberOfElements());
    }
}
posted @ 2020-06-04 10:40  eedc  阅读(2121)  评论(0编辑  收藏  举报