聊一聊CriteriaQuery

Criteria Query,译为条件查询,可理解为程序式、函数式查询。为什么这样说呢?写SQL语句也是编程,但是,SQL就没有什么类、函数这些编程概念了。而Criteria Query就是把查询用一系列对象、方法的调用组合起来,最终结果也得到一条SQL语句。这样做的好处主要是:不用拼接语句,不用写一句很长的代码。写过SQL的人都知道,一个SQL可能很长,但是通常都不是一口气写下来的,而是一小段一小段的写,然后组合出来的,Criteria Query也是这样一点点的“构建”,符合编程习惯,还便于除错。

Criteria Query其实和JPQL是一样的,只不过通常对于JPQL中的很多概念,一般会很少去注意它们的名称,但是在Criteria Query里,都得用一个一个像Expression、Predicate这样的接口及其方法来表达,所以感觉很复杂,但如果把它和JPQL对照起来看,就容易理解了。《Hibernate实战(第二版)》这本书讲Criteria Query的时候就是这么干的,这里必须赞一下。但是要记住是跟JPQL/HQL对照,而不是跟普通 的SQL对照,因为这两者虽然相似,但又不同,主要差别在于:JPQL是面向对象的,而SQL不是。在SQL中可以很自由的关联和投影(选择结果列),JPQL就不是,虽然也可以选择一序列对象或属性作为结果,但如果投影的结果不是一个实体(Entity)的话,那返回的就是一个Object[],这基本上就失去Persistence的意义了。所以通常JPQL是这样写的:

SELECT i FROM Item i;

对应的Native SQL是这样写的

SELECT * FROM item;

然而,一般的SQL教科书都会建议写明字段列表,一个是语义明确,另一个是减少不必要的数据读取和传输。

JPQL/HQL与Native SQL的另一个重要区别是:Native SQL里面别名是可选的,一般只在复杂的查询需要关联或有关联子查询时定义别名,甚至也可以不定义,因为如果没有别名那表或视图本来的名称就是别名。而在JPQL/HQL里,别名是必须的,这里和Criteria Query对照起来就好理解了,因为必须传递一个参数,别名就是这个参数的变量名(形参)。其实Criteria Query和JPQL先有哪个还真不好说,背后中的实现有可能是把JPQL转化为Criteria Query再实现的。

了解了这两个差别,下面这种怪异的写法就很好理解了:

CriteriaBuilder builder = entityManager.getCriteriaBuilder();
CriteriaQuery<Person> criteria = builder.createQuery( Person.class );
Root<Person> root = criteria.from( Person.class );

一开始很不理解为什么createQuery时已经指定了Person.class,后面还要定义一个root并且传给其构建工厂的参数还是Person.class。其实这两处的意义是不一样的,root这里从工厂方法名称来看,要好理解一点,相当于SQL的主表,在Oracle SQL里,会有FROM t1,t2这种同时从两个表里面查询的写法,同样Criteria Query也可以定义两个Root的,当然最好是用Join,实际上Join这个接口就是扩展自Root接口的。而CreateQuery的参数,实际上是指明了查询结果的类型,一般都会是查询实体(主表)的类别,当然也不一定,如果非要查不是实体的东西,比如String也是可以的,当然最后执行查询得到的结果会是List<String>类型的,这里由于只有一个参数,如果查询多个值,又不是实体,那只能传Object[]进去了,查询结果是List<Object[]>类型,还要作类型转换,跟直接用JDBC差不多,没有什么优势,并不实用。CreateQuery这个函数有点像Select子句但还不是Select,只是指明了查询结果的类型,具体的内容还要用Select接口调用来进一步明确。

总结下来就是,SQL可以查的,JPQL也可以查,只是语法不同而已,结合面向对象的特点,这点语法上的差异还是不难理解的。至于CriteriaQuery,由于要用编程语句来表示,会用到很多接口,但这些接口都是与查询中的语法概念一一对应的,结合API资料,参考一下别人写的,熟悉了就好了。

正因为通常用JPQL都是“select 实体 from 实体”,所以Spring Data JPA就把CriteriaQuery封装成了JpaSpecificationExecutor接口,里面定义了findOne、findALL、count等方法,只需要定义一个接口扩展实例化的JpaSpecificationExecutor接口,无需编写实现,像CrudRepository接口一样,Spring会自动提供实现,非常好用。当然,一个查询的最关键部分也就是查询条件,是必须作为参数传递给要调用的方法的,这一部分在Spring被封装成了Specification接口,虽然是只有一个类型参数的模板,但是实现它倒也不是很容易,主要是因为,虽然封装了,但是查询条件是不可能脱离Query存在的,所以要写好Specification接口的实现,必须搞懂或者基本搞懂CriteriaQuery,在Specification接口的唯一虚函数toPredicate中,(Root,CriteriaQuery<?>,CriteriaBuilder)这三个是要作为参数传递的,虽然不用像前面的代码例子那样去写语句生成这些对象,只需要实例化JpaSpecificationExecutor接口,Spring就会创建好这些对象,但是难点从来就不是对象创建而是使用。所以,还是得好好理解CreateQuery是怎样一步步生成Query(语句)的才行。

最后,采用Criteria Query或者其他的编程语句式查询而不是直接写SQL,其实就是为了根据复杂的条件灵活地生成查询条件。Criteria Query里的Predicate(Spring封装成了Specification)是可以组合的,Predicate扩展了Expression<Boolean>,也就是说一个Predicate就是一个布尔表达式,我们可以根据查询条件生成一个一个的简单Predicate然后组合成一个复杂的Predicate。CriteriaBuilder有可变参数的and、or方法可以实现一步一步组合的目的,但是对于实际情况来说,有些查询条件有时需要有时不需要,判断是否需要and或or还是有点啰嗦,而Spring封装的Specification直接有一个and(Specification[])方法,哪怕Specification[]为空都能用。因为一般查询都是用and嘛,这样就方便多了。

粘一段实际代码。

@PostMapping("/user")public String listuser(QueryUserForm queryparam,Model model) {List<User> users = userRepository.findAll((root, query, builder) -> {List<Predicate> predicates = new ArrayList<Predicate>();if (!queryparam.getUsername().isEmpty()) {predicates.add(builder.like(root.get("username"), "%" + queryparam.getUsername() + "%"));}if (!"000000".equals(queryparam.getDistrict_code())) {predicates.add(builder.equal(root.get("district").<String>get("code"), queryparam.getDistrict_code()));}if (queryparam.getOrganization_id() != 0) {predicates.add(builder.equal(root.get("organization").<Integer>get("id"), queryparam.getOrganization_id()));}return builder.and(predicates.toArray(new Predicate[predicates.size()]));});model.addAttribute(users);return "manage/usermanage";}

这段代码用到了λ\lambdaλ表达式和“闭包”,这样子就不用在Business层引用QueryUserForm对象,虽然它只是一个POJO对象,但因为它是用来接受前端查询参数的,所以把它归属为Web层而不应该放在Business层,同时,也不用在Web层引入Root,CriteriaQuery<?>,CriteriaBuilder这些应该是Business(数据层)的对象。相当于在controller里真的只是写了一些查询条件,应该不算业务逻辑吧,因为又没有改变什么。这个例子也可以当作“闭包”应用的一个具体例子吧。

聊一聊CriteriaQuery相关推荐

  1. 聊一聊 软件系统中的“热力学第二定律”

    点击上方蓝色"方志朋",选择"设为星标" 回复"666"获取独家整理的学习资料! 热力学第二定律,也叫"熵增定律".这是 ...

  2. 聊一聊今年实例分割领域的进展和未来展望

    点击上方"视学算法",选择"星标" 干货第一时间送达 作者:林大佬 | 来源:知乎 https://zhuanlan.zhihu.com/p/150321886 ...

  3. 聊一聊2020年实例分割领域的进展和未来展望

    作者|林大佬@知乎 This article was original written by 林大佬, welcome re-post, first come with https://zhuanla ...

  4. 从千万级数据查询来聊一聊索引结构和数据库原理

    在日常工作中我们不可避免地会遇到慢SQL问题,比如笔者在之前的公司时会定期收到DBA彪哥发来的Oracle AWR报告,并特别提示我某条sql近阶段执行明显很慢,可能要优化一下等.对于这样的问题通常大 ...

  5. java cirteria_java – 简单的JPA CriteriaQuery的条件

    所以这是我第一次尝试使用JPA和CriteriaQuery. 我有以下(简化)实体: @Entity @Table(name = "hours") @XmlRootElement ...

  6. 眼耳鼻舌身意,严肃地聊一聊元宇宙的“技术拼图”

    来源:脑极体 元宇宙太太太火了,以至于还没来得及认真聊一聊技术本身,各种炒房团.割韭菜.融资潮.付费课--就纷至沓来,我看不懂但大受震撼. 吃多了瓜,颇有一种"累了毁灭吧"的虚无感 ...

  7. 聊一聊Web端的即时通讯

    聊一聊Web端的即时通讯 Web端实现即时通讯的方法有哪些? - 短轮询 长轮询 iframe流 Flash Socket 轮询 客户端定时向服务器发送Ajax请求,服务器接到请求后马上返回响应信息并 ...

  8. 聊一聊:你觉得这个新Logo值200万吗?

    今天小米正式发布了他的新logo,再一次刷新了大家对设计的认识,很多人纷纷吐槽真是人傻钱多!! 究竟是怎么样的设计让人这么吐槽呢? 我们来看下小米原来的logo: 再看下新的logo: 唔..小编的第 ...

  9. 聊一聊:请假不想说真实原因,你都怎么跟领导讲?

    虽然程序猿的圈子里流行着996工作制,但是大家总归会遇上些家庭琐事需要请假休假,毕竟人生不止眼前的苟且,还有诗与远方. 但是往往我们都不想把一些私密的事情都一五一十的告诉单位里的人知道,尤其是你要去面 ...

最新文章

  1. Incorrect number of FETCH variables
  2. Spring Boot中使用MongoDB数据库
  3. ITK:与矢量型图像应用GradientRecursiveGaussianImageFilter
  4. VTK:图片之ImageIdealHighPass
  5. java全局机制,java实现全局异常机制
  6. 一文读懂「中台」的前世今生
  7. ajax then jquery,使用Jquery.ajax()。then()时无法.catch()错误
  8. VMware开启虚拟化实现CentOS创建KVM
  9. 一文读懂如何用深度学习实现网络安全
  10. 车载双目相机,老兵的二次出征
  11. Imdisk 虚拟磁盘 » A programmer's site
  12. 树莓派价格暴涨买不起?他们自己做了一块价格还不到1/4的开发板平替树莓派,还火到海外去了
  13. python输入税前工资打印税后工资-python-计算个人所得税
  14. 商鞅(约公元前395年-公元前338年)
  15. 苹果使用过程的一些小技巧
  16. 统计学习方法-感知机概括和补充
  17. 我是如何在毕业不久只用1年就升为开发组长的
  18. 那段记忆中的声音:单式评书再现江湖背后的AI技术
  19. 校园点餐系统:点餐、食堂管理、商户管理和菜品管理(Java和MySQL)
  20. 这样的简历,到哪里都是被淘汰的命!

热门文章

  1. 记录如何玩一个二手的H3C WA2620-AGN
  2. 51自学网adc自学书_我必须自学的5件事,学校没有
  3. mongodb 基本原理:索引(Indexes)
  4. 【性能测试】性能测试之性能测试指标详解(性能指标、CPU、内存、负载、磁盘)
  5. TightVNC Java Viewer
  6. Python3 初学实践案例(14)打造一个私人图床服务器
  7. linux vi发现交换文件,vim恢复交换文件中的内容
  8. Linux 系统根目录的含义讲解
  9. GOTS认证辅导,GOTS对运动用品格外宽容,最多含有25%的合成或再生纤维
  10. Mobile APP(Apple IOS app store)特性分析