五种查询方式
父接口方法查询
- 不用改变dao层
@SpringBootTest
@RunWith(SpringRunner.class)
public class Query1Test {
@Autowired
private ArticleDao articleDao;
/**
* 根据主键查询
*/
@Test
public void testFindById() {
//根据一个主键查询
Optional<Article> optional = articleDao.findById(21);
System.out.println(optional.get());
//根据多个主键查询
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(3);
list.add(5);
List<Article> articles = articleDao.findAllById(list);
for (Article article : articles) {
System.out.println(article);
}
}
/**
* 查询所有
*/
@Test
public void testFindAll() {
List<Article> articles = articleDao.findAll();
for (Article article : articles) {
System.out.println(article);
}
}
/**
* 查询所有--排序
*/
@Test
public void testFindAllWithSort() {
//按照aid倒序排列
Sort sort = Sort.by(Sort.Order.desc("aid"));
List<Article> articles = articleDao.findAll(sort);
for (Article article : articles) {
System.out.println(article);
}
}
/**
* 查询所有--分页
*/
@Test
public void testFindAllWithPage() {
//处理分页条件
//page 当前是第几页(从0开始) size 每页大小
Pageable pageable = PageRequest.of(0, 2);
Page<Article> page = articleDao.findAll(pageable);
//总记录数 总页数 每页多少
System.out.println("总记录数:" + page.getTotalElements());
System.out.println("总页数:" + page.getTotalPages());
System.out.println("每页多少:" + page.getSize());
//当前页的元素
List<Article> content = page.getContent();
for (Article article : content) {
System.out.println(article);
}
}
/**
* 查询所有--分页+排序
*/
@Test
public void testFindAllWithPageAndPage() {
//按照aid倒序排列
Sort sort = Sort.by(Sort.Order.desc("aid"));
//处理分页条件
//page 当前是第几页(从0开始) size 每页大小
Pageable pageable = PageRequest.of(0, 2, sort);
Page<Article> page = articleDao.findAll(pageable);
//总记录数 总页数 每页多少
System.out.println("总记录数:" + page.getTotalElements());
System.out.println("总页数:" + page.getTotalPages());
System.out.println("每页多少:" + page.getSize());
//当前页的元素
List<Article> content = page.getContent();
for (Article article : content) {
System.out.println(article);
}
}
}
方法命名规则查询
- 需要在dao接口写方法(idea会有自动提示)
public interface ArticleDao extends JpaRepository<Article, Integer>, JpaSpecificationExecutor<Article> {
//根据标题查询
List<Article> findByTitle(String title);
//根据标题模糊查询
List<Article> findByTitleLike(String title);
//根据标题和作者查询
List<Article> findByTitleAndAuthor(String title, String author);
//根据ID范围查询 > < between in
List<Article> findByAidIsLessThan(Integer aid);
List<Article> findByAidBetween(Integer startAid, Integer endAid);
List<Article> findByAidIn(List<Integer> aids);
//根据创建时间之后查询
List<Article> findByCreateTimeAfter(Date createTime);
}
原理
- SpringData JPA在程序执行的时候会根据方法名称进行解析,并自动生成查询语句进行查询.
- 按照SpringData JPA定义的规则:
- 查询方法以findBy开头,涉及条件查询时,条件的属性用条件关键 字连接,要注意的是:条件属性首字母需大写。
- 框架在进行方法名解析时,会先把方法名多余的前缀截取掉, 然后对剩下部分进行解析。
关键字 | 例子 | 对应的JPQL语句 |
---|---|---|
And | findByLastnameAndFirstname | … where x.lastname = ?1 and x.firstname = ? 2 |
Or | findByLastnameOrFirstname | … where x.lastname = ?1 or x.firstname = ?2 |
Is,Equals | findByFirstnameIs,findByFirstnameEquals | … where x.firstname = ?1 |
Between | findByStartDateBetween | … where x.startDate between ?1 and ?2 |
LessThan | findByAgeLessThan | … where x.age < ?1 |
LessThanEqual | findByAgeLessThanEqual | … where x.age ⇐ ?1 |
GreaterThan | findByAgeGreaterThan | … where x.age > ?1 |
GreaterThanEqual | findByAgeGreaterThanEqual | … where x.age >= ?1 |
After | findByStartDateAfter | … where x.startDate > ?1 |
Before | findByStartDateBefore | … where x.startDate < ?1 |
IsNull | findByAgeIsNull | … where x.age is null |
IsNotNull,NotNull | findByAge(Is)NotNull | … where x.age not null |
Like | findByFirstnameLike | … where x.firstname like ?1 |
NotLike | findByFirstnameNotLike | … where x.firstname not like ?1 |
StartingWith | findByFirstnameStartingWith | … where x.firstname like ?1 (parameter bound withappended %) |
EndingWith | findByFirstnameEndingWith | … where x.firstname like ?1 (parameter bound with prepended %) |
Containing | findByFirstnameContaining | … where x.firstname like ?1 (parameter bound wrapped in%) |
OrderBy | findByAgeOrderByLastnameDesc | … where x.age = ?1 order by x.lastname desc |
Not | findByLastnameNot | … where x.lastname <> ?1 |
In | findByAgeIn(Collection ages) … | … where x.age in ?1 |
NotIn | findByAgeNotIn(Collection age) | … where x.age not in ?1 |
TRUE | findByActiveTrue() | … where x.active = true |
FALSE | findByActiveFalse() | … where x.active = false |
IgnoreCase | findByFirstnameIgnoreCase | … where UPPER(x.firstame) = U |
JPQL查询
- 使用SpringData JPA提供的查询方法已经可以解决大部分的应用场景,但是对于某些业务来说,我们还需要灵活的构造查询条件,这时就可以使用@Query注解,结合JPQL的语句方式完成查询。
- JPQL,全称是Java Persistence Query Language。JPQL语句是JPA中定义的一种查询语言,此种语言的用意是让开发者忽略数据库表和表中的字段,而关注实体类及实体类中的属性。它的写法十分类似于SQL语句的写法,但是要把查询的表名换成实体类名称,把表中的字段名换成实体类的属性名称
- 需要在dao接口写方法及JPQL查询语句
public interface ArticleDao extends JpaRepository<Article, Integer>, JpaSpecificationExecutor<Article> {
//JPQL:类似于SQL语句,但是要使用实体类名代替表名,使用属性名代替字段名[面向对象查询]
//展示位置参数绑定[按照title和author查询]
//占位符从1开始
@Query("from Article a where a.title = ?1 and a.author =?2")
List<Article> findByCondition1(String title, String author);
//展示名字参数绑定
@Query("from Article a where a.title = :title and a.author = :authors")
List<Article> findByCondition2(@Param("title") String title, @Param("authors") String author);
//展示like模糊查询
@Query("from Article a where a.title like %:title%")
List<Article> findByCondition3(@Param("title") String title);
//展示排序查询
@Query("from Article a where a.title like %:title% order by a.aid desc ")
List<Article> findByCondition4(@Param("title") String title);
//展示分页查询
@Query("from Article a where a.title like %:title%")
List<Article> findByCondition5(Pageable pageable, @Param("title") String title);
//展示传入集合参数查询
@Query("from Article a where a.aid in :aids")
List<Article> findByCondition6(@Param("aids") List<Integer> aids);
//展示传入Bean进行查询(SPEL表达式查询)
@Query("from Article a where a.title = :#{#article.title} and a.author = :#{#article.author}")
List<Article> findByCondition7(@Param("article") Article article);
}
注意:
- JPQL类似于SQL语句,但注意
- 使用:实体类名 代替 表名
- 使用:实体类.属性名 代替 字段名
- 获取参数的方式
- ?下标:不推荐
- :参数名:推荐使用(参数必须使用@Param()注解)
- :#{# }:解析对象的属性(参数必须使用@Param()注解)
本地SQL查询
- 基本不会使用,除非是出现非常复杂的业务情况导致SQL非常复杂,JPQL搞不定的时候
- 需要在dao接口写方法及普通的SQL查询语句
public interface ArticleDao extends JpaRepository<Article, Integer>, JpaSpecificationExecutor<Article> {
//本地SQL查询 将nativeQuery改为true
@Query(value = "select * from article a where a.title = ?1 and a.author =?2", nativeQuery = true)
List<Article> findByCondition8(String title, String author);
}
Specifications动态查询
- 有时我们在查询某个实体的时候,给定的条件是不固定的,这时就需要动态构建相应的查询语句
- 在 Spring Data JPA 中可以通过 JpaSpecificationExecutor 接口查询。相比 JPQL,其优势是类型安全,更加的面向对象,缺点是书写比较麻烦。
- 不用改变dao层接口
@SpringBootTest
@RunWith(SpringRunner.class)
public class JpaSpecificationTest {
@Autowired
private ArticleDao articleDao;
/**
* 按照标题和作者进行查询,以不为空的属性作为查询条件
*/
@Test
public void testFindAll() {
//就模拟从从外边传入的变量
String title = "a_3";
String author = "";
List<Article> articles = articleDao.findAll(new Specification<Article>() {
/**
* @param root 代表实体对象,可以通过它的get方法 获取到该字段 然后给该字段设置条件
* @param cq 用于生成SQL语句
* @param cb 用于拼接查询条件
* @return
*/
@Override
public Predicate toPredicate(Root<Article> root, CriteriaQuery<?> cq, CriteriaBuilder cb) {
List<Predicate> list = new ArrayList<>();
if (!StringUtils.isEmpty(title)) {
//拼接作为查询条件
Predicate predicate = cb.equal(root.get("title").as(String.class), title);
list.add(predicate);
}
if (!StringUtils.isEmpty(author)) {
//拼接作为查询条件
Predicate predicate = cb.equal(root.get("author").as(String.class), author);
list.add(predicate);
}
//组合上面的所有查询条件
return cb.and(list.toArray(new Predicate[]{}));
}
});
for (Article article : articles) {
System.out.println(article);
}
}
/**
* 测试动态sql+分页查询
*/
@Test
public void testFindAllWithPage() {
//就模拟从从外边传入的变量
String title = "";
String author = "";
//分页
Pageable pageable = PageRequest.of(0, 3);
Page<Article> page = articleDao.findAll(new Specification<Article>() {
@Override
public Predicate toPredicate(Root<Article> root, CriteriaQuery<?> cq, CriteriaBuilder cb) {
List<Predicate> list = new ArrayList<>();
if (!StringUtils.isEmpty(title)) {
//拼接作为查询条件
Predicate predicate = cb.equal(root.get("title").as(String.class), title);
list.add(predicate);
}
if (!StringUtils.isEmpty(author)) {
//拼接作为查询条件
Predicate predicate = cb.equal(root.get("author").as(String.class), author);
list.add(predicate);
}
return cb.and(list.toArray(new Predicate[]{}));
}
}, pageable);
for (Article article : page.getContent()) {
System.out.println(article);
}
}
/**
* 测试动态sql+分页查询+排序
*/
@Test
public void testFindAllWithPageAndSort() {
//就模拟从从外边传入的变量
String title = "";
String author = "";
//分页 加一个参数Sort
Pageable pageable = PageRequest.of(0, 3, Sort.by(Sort.Order.desc("aid")));
Page<Article> page = articleDao.findAll(new Specification<Article>() {
@Override
public Predicate toPredicate(Root<Article> root, CriteriaQuery<?> cq, CriteriaBuilder cb) {
List<Predicate> list = new ArrayList<>();
if (!StringUtils.isEmpty(title)) {
//拼接作为查询条件
Predicate predicate = cb.equal(root.get("title").as(String.class), title);
list.add(predicate);
}
if (!StringUtils.isEmpty(author)) {
//拼接作为查询条件
Predicate predicate = cb.equal(root.get("author").as(String.class), author);
list.add(predicate);
}
return cb.and(list.toArray(new Predicate[]{}));
}
}, pageable);
for (Article article : page.getContent()) {
System.out.println(article);
}
}
}