1:使用spring-data-jpa很简单,只需要在dao层继承repository接口即可。那么repository接口是什么呢?
可以看到repository接口下面什么都没有,这表明它是一个标记接口。标记接口的作用的什么?标记接口的作用是把当前类纳入到spring的容器中,继承了这个类你会发现
这个标记我想使用idea的同志们都不会陌生的,因为这个表明,当前的类已经被纳入到spring容器中,可以被spring扫描到。那么,除了继承Repository这个接口,还可以怎么做 -> 在接口上加上@RepositoryDefinition注解
RepositoryDefinition注解中有两个属性(domainClass,idClass)一个标识实体类的字节码类型和主键的字节码类型
但是我们一般不用这个注解,这里我们了解一下知道他是怎么搞的就行:无非就是用了spring的aop和反射来实现的。
下面我们来看看spring-data-jpa有哪些接口
那么查询方法的规则和使用又是怎么样的呢?
在接口下面定义的方法必须遵循这些规则
上代码:
1:查询出名字以胡开头,并且年龄小于25
@Test
public void test1(){
// 查询出名字以胡开头,并且年龄小于25
List<User> users = userRepository.findByNameLikeAndAgeLessThan("胡%",25);
users.forEach(p -> System.out.println(p.getName() + " ,年龄" + p.getAge()));
}
2:使用原生的sql进行查询
@Query(value = "select * from user u where u.name like ?1% and age > ?2",nativeQuery = true)
List<User> findUser(String name,int age);
需要使用@Query注解和nativeQuery属性
3: 不使用原生的sql进行查询
@Query(value = "select u from User u where u.salary > ?1")
List<User> findSalary(double salary);
from后面就不能写表名了,只能写表对应的映射名称 ?1代表占位符,当前你也可以使用:如下
@Query(value = "select u from User u where u.id = :id")
User findUser(@Param("id")long id);
这有一个误区:就是冒号后面对应的值应该和@Param里面的值一致,否则或报错
@Query(value = "select u from User u where u.id = :idd")
User findUser(@Param("idd")long id);
这是正确的,注解里面的值和冒号后面的值对应。下面是错误的:
@Query(value = "select u from User u where u.id = :idd")
User findUser(@Param("id")long idd);
4:修改查询
@Modifying
@Query(nativeQuery = true,value = "update user u set u.address = ?2 where u.id = ?1")
void update(Long id,String address);
需要@Modifying注解和@Query注解和@Transactional注解(放在service层) 缺一不可.
5:关联查询什么之类的就不用我多嘴了吧 直接@Query注解加上nativeQuery属性搞起来,原生sql别说你不会哈!!!
分页排序:
这里需要两个对象:Sort和PageRequest
代码如下:
public List<User> getUsers(){
// 安装薪资降序
Sort sort = new Sort(Sort.Direction.DESC,"salary");
// 每页大小十页
PageRequest pageRequest = PageRequest.of(0,10,sort);
List<User> users = userRepsoitory.findAll(pageRequest).getContent();
return users;
}
具体方法点进去看api需要什么参数
那么?更复杂点的动态sql分页排序查询,spring-data-jpa能解决吗?我们知道mybatis可以在xml文件中使用if,for之类的标签来判断,构造动态sql;那spring-data-jpa怎么构建:
这个时候就需要一个强大的对象出马:
Specification 和JpaSpecificationExecutor<T>
代码如下:
public List<User> conditionalQuery(User user){
Specification<User> specification = new Specification<User>() {
@Override
public Predicate toPredicate(Root<User> root, CriteriaQuery<?> cq, CriteriaBuilder cb) {
// root:可用从root中拿到User的属性
// cq:用来查询
// cb:用来构造查询条件
List<Predicate> predicates = new ArrayList<>();
if (!StringUtils.isBlank(user.getName())) {
predicates.add(cb.like(root.get("name"),user.getName() + "%"));
}
if (user.getAge() > 0) {
predicates.add(cb.gt(root.get("age"),user.getAge()));
}
if (user.getSalary() > 0) {
predicates.add(cb.gt(root.get("salary"),user.getSalary()));
}
Predicate result = cb.and(predicates.toArray(new Predicate[predicates.size()]));
return result;
}
};
// 这个排序分页还记得怎么操作吗?
PageRequest pageRequest = PageRequest.of(0,10,Sort.Direction.DESC,"salary");
List<User> users = userRepsoitory.findAll(specification, pageRequest).getContent();
return users;
}
}
dao层需要继承JpaSpecificationExecutor<User>,然后用JpaSpecificationExecutor<User>的findAll方法;
结果如下:
按薪水降序:
[
{
"id": 5,
"name": "胡歌",
"age": 30,
"salary": 2100000,
"address": "上海"
},
{
"id": 17,
"name": "胡歌",
"age": 27,
"salary": 2100000,
"address": "上海"
},
{
"id": 18,
"name": "胡歌",
"age": 30,
"salary": 2100000,
"address": "上海"
},
{
"id": 21,
"name": "胡歌",
"age": 27,
"salary": 2100000,
"address": "上海"
},
{
"id": 19,
"name": "胡歌",
"age": 26,
"salary": 21000,
"address": "上海"
},
{
"id": 20,
"name": "胡歌",
"age": 19,
"salary": 18000,
"address": "上海"
}
]
总结:
1:简单的查询可以直接调用JpaRepository的方法和其命名规范查询
2:关联查询可以使用@Query注解加nativeQuery属性
3:动态sql分页排序查询可以使用Specification和JpaSpecificationExecutor接口