最近在做毕设,今天开始实现搜索功能,最开始的时候是打算上es的话,残酷的现实告诉我时间不够,所以还是简单的使用关系型数据库的模糊查询吧。

在对对应的Jpa接口进行测试的时候,我发现他的运行结果不同预期。

首先,根据文章的标题,摘要,内容进行模糊查询,其一包含关键字便是我们需要的数据。但是文章包含已发布和草稿两种状态,那我需要在查询条件上加上相关的字段,所以我最开始写的方法名,测试代码及输出结果如下:

方法名:
List<Article> findDistinctByArticleModeAndArticleTitleContainingOrArticleSummaryContainingOrArticleContentContaining(int mode,String titleKey,String summaryKey,String contentKey);测试:
List<Article> articles = articleDao.findDistinctByArticleModeAndArticleTitleContainingOrArticleSummaryContainingOrArticleContentContaining(2,"吃","吃","吃");
for(Article article:articles){System.out.println(article.toString());
}控制台输出:
2019-03-29 11:49:38.036  INFO 4216 --- [           main] o.h.h.i.QueryTranslatorFactoryInitiator  : HHH000397: Using ASTQueryTranslatorFactory
Hibernate: select distinct article0_.id as id1_0_, article0_.article_click as article_2_0_, article0_.article_content as article_3_0_, article0_.article_keyword as article_4_0_, article0_.article_like as article_5_0_, article0_.article_mode as article_6_0_, article0_.article_sort_id as article_7_0_, article0_.article_summary as article_8_0_, article0_.article_time as article_9_0_, article0_.article_title as article10_0_, article0_.articleuuid as article11_0_, article0_.last_update_time as last_up12_0_, article0_.user_id as user_id13_0_, article0_.user_name as user_na14_0_ from blog_article article0_ where article0_.article_mode=? and (article0_.article_title like ?) or article0_.article_summary like ? or article0_.article_content like ?
Article(id=842, articleUUID=b4511aa8b8e94fa1a82d9084944a5a8e, articleTitle=吃饭了吗, articleKeyword=没吃呢, articleSummary=没吃呢, articleContent=没吃呢, articleTime=2019-03-29 10:57:43.0, lastUpdateTime=2019-03-29 10:57:43.0, articleClick=0, articleLike=0, articleSortId=0, userId=217, userName=beyond.yang, articleMode=2, hasLike=false, hasClick=false, aNew=false)
Article(id=843, articleUUID=01a5198911014c48a7efc3caac42c559, articleTitle=吃饭了吗, articleKeyword=吃了吗, articleSummary=吃了个鬼, articleContent=没钱吃饭, articleTime=2019-03-29 10:58:56.0, lastUpdateTime=2019-03-29 11:45:36.0, articleClick=1, articleLike=0, articleSortId=0, userId=217, userName=beyond.yang, articleMode=1, hasLike=false, hasClick=false, aNew=false)

输出结果与预期不一致,输出了两篇文章,其中一篇articleMode为1,与预期不符,只要原因在于这个方法生成的sql条件为:

where article0_.article_mode=? and (article0_.article_title like ?) or article0_.article_summary like ? or article0_.article_content like ?

而我期望的结果为:

where article0_.article_mode=? and (article0_.article_title like ? or article0_.article_summary like ? or article0_.article_content like ?)

百度了一下and和or如何组合查询的解决方法,感觉比较复杂,如果通过直接写query的方法,在要支持分页的时候比较麻烦,查到通过jpa本身来解决的方法比较复杂,根据输出的SQL我想到了一种比较简单但是不是特别优雅的方法,方法名,测试代码及输出结果如下:

方法名:
List<Article> findDistinctByArticleModeAndArticleTitleContainingOrArticleModeAndArticleSummaryContainingOrArticleModeAndArticleContentContaining(int mode,String titleKey,int mode1,String summaryKey,int mode2,String contentKey);测试代码:
List<Article> articles = articleDao.findDistinctByArticleModeAndArticleTitleContainingOrArticleModeAndArticleSummaryContainingOrArticleModeAndArticleContentContaining(1,"吃",1,"吃",1,"吃");
for(Article article:articles){System.out.println(article.toString());
}输出结果:
2019-03-29 11:56:54.516  INFO 12008 --- [           main] o.h.h.i.QueryTranslatorFactoryInitiator  : HHH000397: Using ASTQueryTranslatorFactory
Hibernate: select distinct article0_.id as id1_0_, article0_.article_click as article_2_0_, article0_.article_content as article_3_0_, article0_.article_keyword as article_4_0_, article0_.article_like as article_5_0_, article0_.article_mode as article_6_0_, article0_.article_sort_id as article_7_0_, article0_.article_summary as article_8_0_, article0_.article_time as article_9_0_, article0_.article_title as article10_0_, article0_.articleuuid as article11_0_, article0_.last_update_time as last_up12_0_, article0_.user_id as user_id13_0_, article0_.user_name as user_na14_0_ from blog_article article0_ where article0_.article_mode=? and (article0_.article_title like ?) or article0_.article_mode=? and (article0_.article_summary like ?) or article0_.article_mode=? and (article0_.article_content like ?)
Article(id=843, articleUUID=01a5198911014c48a7efc3caac42c559, articleTitle=吃饭了吗, articleKeyword=吃了吗, articleSummary=吃了个鬼, articleContent=没钱吃饭, articleTime=2019-03-29 10:58:56.0, lastUpdateTime=2019-03-29 11:45:36.0, articleClick=1, articleLike=0, articleSortId=0, userId=217, userName=beyond.yang, articleMode=1, hasLike=false, hasClick=false, aNew=false)

可以看到,这个方法生成的查询条件:where article0_.article_mode=? and (article0_.article_title like ?) or article0_.article_mode=? and (article0_.article_summary like ?) or article0_.article_mode=? and (article0_.article_content like ?)

虽然这样的写法有点奇怪,不过足够简单的解决了问题,之后要加上分页支持只需要在方法参数加上Pageable

==================================分割线==================================

使用Specification正儿八经的解决方法

具体做法是实现Specification接口的toPredicate方法

通过CriteraBuilder创建需要的Predicate

首先,生成三个需要like的条件生成Predicate,由于有多个条件,你并不能保障每个条件都传进来,所以使用List容器转起来

我们需要的where限制是where article0_.article_mode=? and (article0_.article_title like ? or article0_.article_summary like ? or article0_.article_content like ?),也就是三个模糊匹配like的条件,需要先进行and操作,由于有多个条件,你并不能保障每个条件都传进来,所以使用List容器转起来,生成and条件的Predicate的时候转换为应用类型对应的数据

接下来,生成article_mode的Predicate,直接用equal

最后直接将两个Predicate通过query.where返回,生成的查询调价便是我们期望的

class ArticleSearchSpecification implements Specification{private Article article;public ArticleSearchSpecification(Article article){this.article = article;}@Overridepublic Predicate toPredicate(Root root, CriteriaQuery query, CriteriaBuilder cb) {List<Predicate> predicates = new ArrayList<>();if(article.getArticleTitle() != null && !article.getArticleTitle().equals("")){predicates.add(cb.like(root.get("articleTitle").as(String.class),"%"+article.getArticleTitle()+"%"));}if(article.getArticleSummary() != null && !article.getArticleSummary().equals("")){predicates.add(cb.like(root.get("articleSummary").as(String.class),"%"+article.getArticleSummary()+"%"));}if(article.getArticleContent() != null && !article.getArticleContent().equals("")){predicates.add(cb.like(root.get("articleContent").as(String.class),"%"+article.getArticleContent()+"%"));}Predicate predicateOr = cb.or(predicates.toArray(new Predicate[predicates.size()]));predicateOr = cb.and(predicateOr);Predicate predicateAnd;if(article.getArticleMode() != ArticleConstant.ARTICLE_DRAFT&& article.getArticleMode()!= ArticleConstant.ARTICLE_PUBLIC){predicateAnd = cb.equal(root.get("articleMode"),ArticleConstant.ARTICLE_PUBLIC);}else{predicateAnd = cb.equal(root.get("articleMode"),article.getArticleMode());}return query.where(predicateOr,predicateAnd).getRestriction();}
}

Spring Data Jpa And 和 Or 组合使用的简单方式相关推荐

  1. Spring Data JPA 写SQL语句也可以如此简单

    在使用 Spring Data JPA 的时候,通常我们只需要继承 JpaRepository 就能获得大部分常用的增删改查的方法.有时候我们需要自定义一些查询方法,可以写自定义 HQL 语句 像这样 ...

  2. Spring Security+Spring Data Jpa 强强联手,安全管理只有更简单!

    Spring Security+Spring Data Jpa 强强联手,安全管理没有简单,只有更简单! 这周忙着更新 OAuth2,Spring Security 也抽空来一篇. Spring Se ...

  3. Spring Data JPA 复杂/多条件组合分页查询

    推荐视频: http://www.icoolxue.com/album/show/358 public Map<String, Object> getWeeklyBySearch(fina ...

  4. Spring Data JPA教程

    在Java类或对象与关系数据库之间管理数据是一项非常繁琐且棘手的任务. DAO层通常包含许多样板代码,应简化这些样板代码,以减少代码行数并使代码可重复使用. 在本教程中,我们将讨论Spring数据的J ...

  5. 【Spring Data JPA自学笔记三】Spring Data JPA的基础和高级查询方法

    文章目录 调用接口的基础方法查询 Repository CrudRepository PagingAndSortingRepository JPARepository JpaSpecification ...

  6. spring data jpa从入门到精通_Spring Data JPA的简单入门

    前言 spring data JPA是spring团队打造的sping生态全家桶的一部分,本身内核使用的是hibernate核心源码,用来作为了解java持久层框架基本构成的样本是再好不过的选择.最近 ...

  7. Spring Data JPA教程:简介

    创建使用Java Persistence API的存储库是一个繁琐的过程,需要大量时间,并且需要大量样板代码. 通过执行以下步骤,我们可以消除一些样板代码: 创建一个抽象的基础存储库类,该类为实体提供 ...

  8. Spring Data JPA的持久层

    1.概述 本文将重点介绍Spring 3.1,JPA和Spring Data的持久层的配置和实现. 有关使用基于Java的配置和项目的基本Maven pom设置Spring上下文的分步介绍,请参阅本文 ...

  9. Spring Data JPA入门

    见:http://sishuok.com/forum/blogPost/list/7000.html Spring Data是什么 Spring Data是一个用于简化数据库访问,并支持云服务的开源框 ...

最新文章

  1. HTML表格颜色按条件填充,Excel单元格能否根据条件填充颜色?
  2. 库克退休前的最后一战:不是苹果汽车而是……
  3. egg 自学入门demo分享
  4. Android studio 自定义打包apk名
  5. ALV Checkbox 单行灰显
  6. 2016/3/16 高级查询 ①连接查询 ②联合查询 ③子查询 无关 相关
  7. Open 语法的使用
  8. Android开发之自定义view进行旋转动画
  9. 使用Java :: Geci生成setter和getter
  10. cr全称是什么意思_轻生未遂?她到底经历了些什么......
  11. java after 函数_函数周期表丨信息丨值丨ISONORAFTER
  12. 咏南IOCP REST中间件
  13. lopatkin俄大神精简中文系统Windows 10 Enterprise 2016 LTSB 14393.577 x86-x64 ZH-CN PIP
  14. 计算机专业毕设论文题目大全(一)
  15. 如何给服务器重装系统时,安装Raid驱动
  16. 【量化笔记】股票收益率与风险计算
  17. 打破双亲委派么,怎么打破_打破统一垃圾收集规则
  18. 二叉树+链表+字符串+栈和队列高频面试题合集,已开源下载
  19. html静态网站登陆验证,静态页面js加密URL密码验证
  20. Java发送手机短信

热门文章

  1. 多种可以反手“调戏”面试官的方案
  2. 若依ajax返回数据,Ajax
  3. 如何关闭linux系统的53端口,3种关闭linux系统端口方法(示例代码)
  4. AX版Flash 1月12日之后继续使用Flash的方法
  5. stylegan3:alias-free generative adversarial networks
  6. Android使用百度地图api获取定位信息(经纬度)
  7. 5G时代,基带芯片下的ARM与X86架构……
  8. Android 每周一个小轮子之 学习仿网易云广场歌单的效果
  9. 复杂网络 网络数据集
  10. 一个普通人毕业2年学习面试及工作总结