Spring Data Jpa 自定义查询定义规则 及事务、分页
关于SpringData JPA查询的定义
- 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
,?2
@Query(nativeQuery = false,value = " SELECT p FROM User p WHERE id = ?1")
User readId(Integer id);
[:][]
,[...:][参数名]
,参数名必须是实体的属性名,并且方法参数上加上对应的注解@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);
分页对象
-
要求自定义的Repository必须继承了PagingAndSortingRepository或者他的子类JpaRepository
-
分页对象是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());
}
}