SpringBoot2.x使用Data-JPA系列三

Repository接口

继承JpaResposity的原理及基本用法

JpaResposity这个接口是一个核心的接口,直接继承这个接口,就可以完成CURD的基本操作了。接口继承的路径如下图:

Paste_Image.png

 

最高层的Repository<T,ID>是一个空接口,我们定义的数据访问类只要实现这个接口,这个数据访问类就可以被spring data所管理,就此可以使用spring为我们提供操作方法(在原来的spring data中我们需要配置很多和Spring Data Repository相关的设置,但是现在有了spring boot,全部都已经自动配置好了)。这个接口要实现有两个泛型参数,第一个T表示实体类,第二个表示主键的类型, 其中 JpaRepository 继承了2个接口 PagingAndSortingRepository 和QueryByExampleExecutor


复制代码
public interface StudentRepository extends JpaRepository<Student,Integer> {
​
    @Query("select s from Student s where s.id=?1")
    public Student loadById(int id);
​
    //根据地址和年龄进行查询
    public List<Student> findByAddressAndAge(String address, int age);
    //根据id获取对象,即可返回对象,也可以返回列表
    public Student readById(int id);
    //根据id获取列表,这里如果确定只有一个对象,也可以返回对象
    public List<Student> getById(int id);
    //根据id获取一个对象,同样也可以返回列表
    public Student findById(int id);
}
复制代码

 

这个接口实现了JpaRepository接口,这里有两种使用JpaRepository的基本方法

  • 第一种方法增加了一个@Query的annotation,通过这个声明,Spring Data JPA就知道该使用什么HQL去查询数据,?1表示用方法中的第一个参数。

  • 第二种方法我们并没有定义任何的Annotation,在Spring Data JPA中提供了一种衍生查询,只要函数的声明有findBy,getBy,readBy即可,findByAddressAnAge表示根据address和age进行查询,注意大小写以及与对应Bean的属性对应,方法的第一个参数就是address,第二个参数就是age,这些方法的返回值可以是一个列表,也可以是一个对象,Spring Data JPA会自动根据返回类型来进行处理。我们不用写实现类,Spring Data JPA会自动帮助我们实现查询。

Query 基本的使用方法

JPQL 与 Hibernate的HQL类似

  • @Query 注解,标注在方法上,优先于 @NameQuery,也优先于在xml中定义的。

  • 最基本使用方法如下


@Query("select u from User u where u.emailAddress = ?1")  
 User findByEmailAddress(String emailAddress); 

 

  • Like使用如下


 @Query("select u from User u where u.firstname like %?1")   
List<User> findByFirstnameEndsWith(String firstname);

 

  • 原生的SQL

@Query(value = "SELECT * FROM USERS WHERE EMAIL_ADDRESS = ?1", nativeQuery = true)   
User findByEmailAddress(String emailAddress);

 

原生SQL目前不支持动态排序,如果使用分页的查询,可以考虑如下方式


@Query(value = "SELECT * FROM USERS WHERE LASTNAME = ?1",    
countQuery = "SELECT count(*) FROM USERS WHERE LASTNAME = ?1",    
nativeQuery = true)   
Page<User> findByLastname(String lastname, Pageable pageable); 

 

  • @Query中使用排序


复制代码
public interface UserRepository extends JpaRepository<User, Long> {
   @Query("select u from User u where u.lastname like ?1%")   
    List<User> findByAndSort(String lastname, Sort sort);
    @Query("select u.id, LENGTH(u.firstname) as fn_len from User u where u.lastname like ?1%")   
    List<Object[]> findByAsArrayAndSort(String lastname, Sort sort);
 }
repo.findByAndSort("lannister", new Sort("firstname"));
repo.findByAndSort("stark", new Sort("LENGTH(firstname)")); //这个是错误示例,不能这么用,需要参考下一条
repo.findByAndSort("targaryen", JpaSort.unsafe("LENGTH(firstname)")); 
repo.findByAsArrayAndSort("bolton", new Sort("fn_len")); 
复制代码

 

          
  • 使用参数名称


 @Query("select u from User u where u.firstname = :firstname or u.lastname = :lastname")   
User findByLastnameOrFirstname(@Param("lastname") String lastname, @Param("firstname") String firstname); 

 

  • Query 带修改


@Modifying 
@Query("update User u set u.firstname = ?1 where u.lastname = ?2") 
int setFixedFirstnameFor(String firstname, String lastname);

 

JpaResposity根据名称生成查询

这个是spring-data-jpa最常见的部分了,不多解释,留一个备份在,被查即可。

image.png

image.png

Repository为什么只有接口就可以直接使用

这个问题我解释起来有些信心不足,不过可以肯定的是,我知道是什么,为什么还不是很清楚。 在Spring-data-Jpa中有个默认的实现类org.springframework.data.jpa.repository.support.SimpleJpaRepository


@Repository
@Transactional(readOnly = true)
public class SimpleJpaRepository<T, ID extends Serializable>
        implements JpaRepository<T, ID>, JpaSpecificationExecutor<T> {
//内容省略
}

 

EntityManager 是Jpa中操作数据库的类,在原生的Hibernate中叫做Session,在MyBatis中叫做SqlSession。 Spring-data通过JpaRepositoryFactory将SimpleJpaRepository注入。所以我们不需要写实现类就可以了。

Jpa自定义查询

自定义查询,jpa已经帮我们完成了很多,只要我们自己写自己需要的条件就可以了,一般会写一个匿名类,重写toPredicate方法来完成。初步先记录下来。


复制代码
@Override
    public Page<Student> search(final Student student, PageInfo page) {
        return studentRepository.findAll(new Specification<Student>() {
            @Override
            public Predicate toPredicate(Root<Student> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
                
                Predicate stuNameLike = null;
                if(null != student && !StringUtils.isEmpty(student.getName())) {
                    stuNameLike = cb.like(root.<String> get("name"), "%" + student.getName() + "%");
                }
                
                Predicate clazzNameLike = null;
                if(null != student && null != student.getClazz() && !StringUtils.isEmpty(student.getClazz().getName())) {
                    clazzNameLike = cb.like(root.<String> get("clazz").<String> get("name"), "%" + student.getClazz().getName() + "%");
                }
​
                return cb.and(stuNameLike,clazzNameLike);
            }
        }, new PageRequest(page.getPage() - 1, page.getLimit(), new Sort(Direction.DESC, page.getSortName())));
    }
复制代码

 

再来一个例子(xx or xx)and (xxx or xx)的处理

复制代码
public void testSpecificaiton2() {
//第一个Specification定义了两个or的组合
Specification<Student> s1 = new Specification<Student>() {
    @Override
    public Predicate toPredicate(Root<Student> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
        Predicate p1 = criteriaBuilder.equal(root.get("id"),"2");
        Predicate p2 = criteriaBuilder.equal(root.get("id"),"3");
        return criteriaBuilder.or(p1,p2);
    }
};
//第二个Specification定义了两个or的组合
Specification<Student> s2 = new Specification<Student>() {
    @Override
    public Predicate toPredicate(Root<Student> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
        Predicate p1 = criteriaBuilder.like(root.get("address"),"zt%");
        Predicate p2 = criteriaBuilder.like(root.get("name"),"foo%");
        return criteriaBuilder.or(p1,p2);
    }
};
//通过Specifications将两个Specification连接起来,第一个条件加where,第二个是and
List<Student> stus = studentSpecificationRepository.findAll(Specifications.where(s1).and(s2));
​
    Assert.assertEquals(1,stus.size());
    Assert.assertEquals(3,stus.get(0).getId());
}
复制代码

 

 

posted on   没刮胡子  阅读(373)  评论(0编辑  收藏  举报

编辑推荐:
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· winform 绘制太阳,地球,月球 运作规律
· 上周热点回顾(3.3-3.9)
点击右上角即可分享
微信分享提示