SpringBoot2.x使用Data-JPA系列三
继承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()); }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· winform 绘制太阳,地球,月球 运作规律
· 上周热点回顾(3.3-3.9)