Spring Data Jpa And 和 Or 组合使用的简单方式
最近在做毕设,今天开始实现搜索功能,最开始的时候是打算上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 组合使用的简单方式相关推荐
- Spring Data JPA 写SQL语句也可以如此简单
在使用 Spring Data JPA 的时候,通常我们只需要继承 JpaRepository 就能获得大部分常用的增删改查的方法.有时候我们需要自定义一些查询方法,可以写自定义 HQL 语句 像这样 ...
- Spring Security+Spring Data Jpa 强强联手,安全管理只有更简单!
Spring Security+Spring Data Jpa 强强联手,安全管理没有简单,只有更简单! 这周忙着更新 OAuth2,Spring Security 也抽空来一篇. Spring Se ...
- Spring Data JPA 复杂/多条件组合分页查询
推荐视频: http://www.icoolxue.com/album/show/358 public Map<String, Object> getWeeklyBySearch(fina ...
- Spring Data JPA教程
在Java类或对象与关系数据库之间管理数据是一项非常繁琐且棘手的任务. DAO层通常包含许多样板代码,应简化这些样板代码,以减少代码行数并使代码可重复使用. 在本教程中,我们将讨论Spring数据的J ...
- 【Spring Data JPA自学笔记三】Spring Data JPA的基础和高级查询方法
文章目录 调用接口的基础方法查询 Repository CrudRepository PagingAndSortingRepository JPARepository JpaSpecification ...
- spring data jpa从入门到精通_Spring Data JPA的简单入门
前言 spring data JPA是spring团队打造的sping生态全家桶的一部分,本身内核使用的是hibernate核心源码,用来作为了解java持久层框架基本构成的样本是再好不过的选择.最近 ...
- Spring Data JPA教程:简介
创建使用Java Persistence API的存储库是一个繁琐的过程,需要大量时间,并且需要大量样板代码. 通过执行以下步骤,我们可以消除一些样板代码: 创建一个抽象的基础存储库类,该类为实体提供 ...
- Spring Data JPA的持久层
1.概述 本文将重点介绍Spring 3.1,JPA和Spring Data的持久层的配置和实现. 有关使用基于Java的配置和项目的基本Maven pom设置Spring上下文的分步介绍,请参阅本文 ...
- Spring Data JPA入门
见:http://sishuok.com/forum/blogPost/list/7000.html Spring Data是什么 Spring Data是一个用于简化数据库访问,并支持云服务的开源框 ...
最新文章
- HTML表格颜色按条件填充,Excel单元格能否根据条件填充颜色?
- 库克退休前的最后一战:不是苹果汽车而是……
- egg 自学入门demo分享
- Android studio 自定义打包apk名
- ALV Checkbox 单行灰显
- 2016/3/16 高级查询 ①连接查询 ②联合查询 ③子查询 无关 相关
- Open 语法的使用
- Android开发之自定义view进行旋转动画
- 使用Java :: Geci生成setter和getter
- cr全称是什么意思_轻生未遂?她到底经历了些什么......
- java after 函数_函数周期表丨信息丨值丨ISONORAFTER
- 咏南IOCP REST中间件
- lopatkin俄大神精简中文系统Windows 10 Enterprise 2016 LTSB 14393.577 x86-x64 ZH-CN PIP
- 计算机专业毕设论文题目大全(一)
- 如何给服务器重装系统时,安装Raid驱动
- 【量化笔记】股票收益率与风险计算
- 打破双亲委派么,怎么打破_打破统一垃圾收集规则
- 二叉树+链表+字符串+栈和队列高频面试题合集,已开源下载
- html静态网站登陆验证,静态页面js加密URL密码验证
- Java发送手机短信
热门文章
- 多种可以反手“调戏”面试官的方案
- 若依ajax返回数据,Ajax
- 如何关闭linux系统的53端口,3种关闭linux系统端口方法(示例代码)
- AX版Flash 1月12日之后继续使用Flash的方法
- stylegan3:alias-free generative adversarial networks
- Android使用百度地图api获取定位信息(经纬度)
- 5G时代,基带芯片下的ARM与X86架构……
- Android 每周一个小轮子之 学习仿网易云广场歌单的效果
- 复杂网络 网络数据集
- 一个普通人毕业2年学习面试及工作总结