添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

在企业级项目开发过程中,往往会经常用到数据库内的聚合函数,一般ORM框架应对这种逻辑问题时都会采用编写原生的SQL来处理,而QueryDSL完美的解决了这个问题,它内置了SQL所有的聚合函数下面我们简单介绍我们常用的几个聚合函数。

基于SpringBoot平台整合QueryDSL完成常用聚合函数使用。

我们使用idea来创建一个SpringBoot项目,pom.xml配置文件依赖如下所示:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.yuqiyu.querydsl.sample</groupId>
    <artifactId>chapter6</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>war</packaging>
    <name>chapter6</name>
    <description>Demo project for Spring Boot</description>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.4.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
        <!--阿里巴巴数据库连接池,专为监控而生 -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.0.26</version>
        </dependency>
        <!-- 阿里巴巴fastjson,解析json视图 -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.15</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
            <!--<scope>provided</scope>-->
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <!--queryDSL-->
        <dependency>
            <groupId>com.querydsl</groupId>
            <artifactId>querydsl-jpa</artifactId>
            <version>${querydsl.version}</version>
        </dependency>
        <dependency>
            <groupId>com.querydsl</groupId>
            <artifactId>querydsl-apt</artifactId>
            <version>${querydsl.version}</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.16.16</version>
        </dependency>
        <dependency>
            <groupId>javax.inject</groupId>
            <artifactId>javax.inject</artifactId>
            <version>1</version>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
            <!--添加QueryDSL插件支持-->
            <plugin>
                <groupId>com.mysema.maven</groupId>
                <artifactId>apt-maven-plugin</artifactId>
                <version>1.1.3</version>
                <executions>
                    <execution>
                        <goals>
                            <goal>process</goal>
                        </goals>
                        <configuration>
                            <outputDirectory>target/generated-sources/java</outputDirectory>
                            <processor>com.querydsl.apt.jpa.JPAAnnotationProcessor</processor>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>

上面内的QueryDSL这里就不多做讲解了,如有疑问请查看 第一章:Maven环境下如何配置QueryDSL环境

创建数据表

下面我们来创建一个张数据表来讲解本章的内容,表结构如下所示:

Navicat MariaDB Data Transfer Source Server : local Source Server Version : 100108 Source Host : localhost:3306 Source Database : test Target Server Type : MariaDB Target Server Version : 100108 File Encoding : 65001 Date: 2017-07-13 15:57:37 SET FOREIGN_KEY_CHECKS= 0 ; -- ---------------------------- -- Table structure for users -- ---------------------------- DROP TABLE IF EXISTS `users` ; CREATE TABLE `users` ( `u_id` int ( 11 ) NOT NULL AUTO_INCREMENT COMMENT '主键编号' , `u_username` varchar ( 50 ) CHARACTER SET utf8 DEFAULT NULL COMMENT '用户名' , `u_age` int ( 10 ) DEFAULT NULL COMMENT '年龄' , `u_score` double ( 8 , 2 ) DEFAULT NULL COMMENT '积分' , PRIMARY KEY ( `u_id` ) ) ENGINE=MyISAM AUTO_INCREMENT= 5 DEFAULT CHARSET=latin1; -- ---------------------------- -- Records of users -- ---------------------------- INSERT INTO `users` VALUES ( '1' , 'admin' , '12' , '45.70' ); INSERT INTO `users` VALUES ( '2' , 'hengyu' , '23' , '56.40' ); INSERT INTO `users` VALUES ( '3' , 'test' , '22' , '67.80' ); INSERT INTO `users` VALUES ( '4' , 'jocker' , '25' , '99.00' );

我们简单创建了一张用户信息表,表内的年龄、积分是我们本章主要使用到的字段,下面我们就开始来讲解本章的内容。

我们对应数据库内的表结构创建我们需要的实体并添加JPA的映射,实体代码如下所示:

package com.yuqiyu.querydsl.sample.chapter6.bean;
import lombok.Data;
import javax.persistence.*;
 * ========================
 * Created with IntelliJ IDEA.
 * User:恒宇少年
 * Date:2017/7/12
 * Time:10:58
 * 码云:http://git.oschina.net/jnyqy
 * ========================
@Entity
@Table(name = "users")
@Data
public class UserBean
    @GeneratedValue
    @Column(name = "u_id")
    private Long id;
    @Column(name = "u_username")
    private String name;
    @Column(name = "u_age")
    private int age;
    @Column(name = "u_score")
    private double socre;

如果对@Data注解有疑问,大家可以去GitHub查一下lombok开源项目。
我们的实体已经创建完成,下面我们开始使用maven compile命令完成QueryDSL查询实体的创建,我们找到Maven Projects窗口,展开Lifecyle组,双击compile命令即可,如下图1所示:

图1
查看控制台输出Build Success表示项目构建完成,我们就可以在target/generated-sources/java目录下看到自动生成的查询实体源码。

创建控制器

本章创建控制器的方法与前几章一致,采用@PostConstruct来初始化JPAQueryFactory实体对象,控制器代码如下所示:

package com.yuqiyu.querydsl.sample.chapter6.controller;
import com.querydsl.jpa.impl.JPAQueryFactory;
import com.yuqiyu.querydsl.sample.chapter6.bean.UserBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.PostConstruct;
import javax.persistence.EntityManager;
import java.util.List;
 * ========================
 * Created with IntelliJ IDEA.
 * User:恒宇少年
 * Date:2017/7/12
 * Time:10:59
 * 码云:http://git.oschina.net/jnyqy
 * ========================
@RestController
public class UserController
    //实体管理对象
    @Autowired
    private EntityManager entityManager;
    //queryDSL,JPA查询工厂
    private JPAQueryFactory queryFactory;
    //实例化查询工厂
    @PostConstruct
    public void init()
        queryFactory = new JPAQueryFactory(entityManager);

下面我们开始编写聚合函数代码。

Count函数

我们现在的需求是查询用户表内的总条数,控制器方法代码如下所示:

* count聚合函数 * @return @RequestMapping(value = "/countExample") public long countExample() //用户查询实体 QUserBean _Q_user = QUserBean.userBean; return queryFactory .select(_Q_user.id.count())//根据主键查询总条数 .from(_Q_user) .fetchOne();//返回总条数

可以看到我们根据id这个字段进行了count聚合,当然我们也可以根据实体内任意字段进行count聚合,我们一般会根据主键来进行聚合,因为主键默认有索引,效率会更高。

这里要注意一点,我们使用的fetchOne方法返回的类型完全是根据select方法内单个参数的类型对应的。

下面我们来启动项目测试下我们这个count聚合是否有效,项目启动完成后我们访问地址http://127.0.0.1:8080/countExample,界面输入内容如下图2所示:

图2
我们再来看下控制台输出的生成SQL是否为我们预期的效果,SQL如下所示:

Hibernate: 
    select
        count(userbean0_.u_id) as col_0_0_ 
        users userbean0_

可以看到QueryDSL自动生成的SQL跟我们预期的是一样的,我又被QueryDSL的方便深深的折服了。

Sum函数

接下来我们需要查询所有用户分数总和,代码如下所示:

* sum聚合函数 * @return @RequestMapping(value = "/sumExample") public double sumExample() //用户查询实体 QUserBean _Q_user = QUserBean.userBean; return queryFactory .select(_Q_user.socre.sum())//查询积分总数 .from(_Q_user) .fetchOne();//返回积分总数

我们重启项目测试我们的sum聚合函数是否能够查询出总分数,访问地址http://127.0.0.1:8080/sumExample界面输出内容如下图3所示:
图3
我们再来查看下控制台输出的生成SQL,如下所示:

Hibernate: 
    select
        sum(userbean0_.u_score) as col_0_0_ 
        users userbean0_

也是没问题的,很智能,可谓是指哪打哪。

Avg函数

下面我们又有新的需求了,需要查询下积分的平均值,代码如下所示:

* avg聚合函数 * @return @RequestMapping(value = "/avgExample") public double avgExample() //用户查询实体 QUserBean _Q_user = QUserBean.userBean; return queryFactory .select(_Q_user.socre.avg())//查询积分平均值 .from(_Q_user) .fetchOne();//返回平均值

访问映射地址界面输出内容如下图4所示:
图4
我们再来看下控制台输出的SQL,如下所示:

Hibernate: 
    select
        avg(userbean0_.u_score) as col_0_0_ 
        users userbean0_

可以看到QueryDSL自动根据积分字段进行了avg聚合实现。

Max函数

接下来我们来查询用户最大积分值,代码如下所示:

* max聚合函数 * @return @RequestMapping(value = "/maxExample") public double maxExample() //用户查询实体 QUserBean _Q_user = QUserBean.userBean; return queryFactory .select(_Q_user.socre.max())//查询最大积分 .from(_Q_user) .fetchOne();//返回最大积分

我们根据积分字段调用max方法即可获取最大积分,然后调用fetchOne方法就能够返回double类型的最大积分值。我们重启下项目访问路径http://127.0.0.1:8080/maxExample界面输出内容如下图5所示:
图5
下面再来看下控制台输出的SQL,如下所示:

Hibernate: 
    select
        max(userbean0_.u_score) as col_0_0_ 
        users userbean0_

到现在为止我们得出来了一个结论,如果原生SQL内聚合函数是作用在字段上,在QueryDSL内使用方法则是查询属性.xxx函数,那么接下来的聚合函数作用域就不是字段了而变成了表。

Group By函数

我们的分组函数该如何使用呢?下面我们根据积分进行分组并且仅查询年龄大于22岁的数据,控制器代码如下所示:

* group by & having聚合函数 * @return @RequestMapping(value = "/groupByExample") public List<UserBean> groupByExample() //用户查询实体 QUserBean _Q_user = QUserBean.userBean; return queryFactory .select(_Q_user) .from(_Q_user) .groupBy(_Q_user.socre)//根据积分分组 .having(_Q_user.age.gt(22))//并且年龄大于22岁 .fetch();//返回用户列表

因为Group By函数作用域不是字段而是表,所以会与select、from方法同级,跟原生SQL一样使用Group By进行查询时查询条件不能使用where,而是having!在QueryDSL内也是一样,因为QueryDSL完全遵循了SQL标准。
下面我们重启下项目访问地址http://127.0.0.1:8080/groupByExample看下效果,如下图6所示:
图6
可以看到我们读取到数据是正确的,仅仅查询出了大于22岁的数据。下面我们再来看下控制台输出的SQL如下所示:

Hibernate: 
    select
        userbean0_.u_id as u_id1_0_,
        userbean0_.u_age as u_age2_0_,
        userbean0_.u_username as u_userna3_0_,
        userbean0_.u_score as u_score4_0_ 
        users userbean0_ 
    group by
        userbean0_.u_score 
    having
        userbean0_.u_age>?

可以看到SQL是根据积分字段进行分组并且查询年龄大于22岁的列表。

以上内容就是本章的全部讲解,我们不管是从上面的代码还是之前章节的代码可以得到一个QueryDSL的设计主导方向,QueryDSL完全遵循SQL标准进行设计,SQL内的作用域的关键字在QueryDSL内也是通过,不过展现形式不同罢了。
上面函数不是全部的聚合函数,项目中如果需要其他函数可按照本章的思路去写。

本章代码已经上传码云:
SpringBoot配套源码地址:https://gitee.com/hengboy/spring-boot-chapter
SpringCloud配套源码地址:https://gitee.com/hengboy/spring-cloud-chapter
SpringBoot相关系列文章请访问:目录:SpringBoot学习目录
QueryDSL相关系列文章请访问:QueryDSL通用查询框架学习目录
SpringDataJPA相关系列文章请访问:目录:SpringDataJPA学习目录
感谢阅读!

更多干货文章扫码关注微信公众号

加入知识星球,恒宇少年带你走以后的技术道路!!!

在企业级项目开发过程中,往往会经常用到数据库内的聚合函数,一般ORM框架应对这种逻辑问题时都会采用编写原生的SQL来处理,而QueryDSL完美的解决了这个问题,它内置了SQL所有的聚合函数下面我们简单介绍我们常用的几个聚合函数。本章目标基于SpringBoot平台整合QueryDSL完成常用聚合函数使用。构建项目我们使用idea来创建一个SpringBoot项目,pom....
querydsl使用groupby的一个不记录 java.lang.IllegalArgumentException: org.hibernate.hql.internal.ast.QuerySyntaxException: expecting CLOSE, found ',' 最近发现在使用Querydsl fetchCount()的时候使用groupBy()会报错,经过多次测试后发现,如果使用fetchCount()之前使用了groupBy()并且有多个字段分组,如groupBy(qUser.name,
使用Querydsl和Spring Data制作“ REST查询语言”的示例 借助和Spring Data扩展,我们可以轻松实现“ REST查询语言”来过滤特定实体的数据。 为此,我们可以从QuerydslPredicateExecutor扩展QuerydslPredicateExecutor ,将带有注释@QuerydslPredicate Predicate添加为REST控制器方法的参数,并在存储库的findAll方法中使用它。 然后,我们可以请求具有基本过滤,分页和排序支持的实体数据,例如,如下所示: GET /people?name=John&size=10&page=2,sort=name,desc 其中name是我们实体Person的属性, size是页面大小, page是当前页面的数量, sort是一个参数,该参数告诉您按name对数据进行降序排序。 publi
使用group by分组后展示其他字段 需要加any_value(字段名) 例如: select time from student group by time 还想获取其他字段信息 如下: select time,any_value(id),any_value(name),any_value(sex),any_value(grade) from student group by time,即可实现对其他字段信息的获取. JPA或MongoDB的Spring数据; 所有项目都很简单,专为学习目的而开发。 每个项目都设置数据,并利用来自各种过滤器,排序和分页的灵活搜索/查询功能。 每个项目都展示了一种持久性方法,探索了前面提到的技术。 看: querydsl-jpa:使用Spring MVC和Spring Boot开发的Java Web应用程序,演示了如何使用QueryDSL和JPA / Hibernate。 使用的数据库是HSQLDB。 前端是使用JQuery和Foundation开发的。 querydsl-spring-data:使用Spring MVC和Spring Boot开发的Java Web应用程序演示了Spring Data JPA如何与QueryDSL和JPA一起使用。 前端是
spring-boot-querydsl-bug 说明 querydsl 集合和 spring boot 的 javac 调用类路径问题 如果作为 spring boot 应用程序运行,它将调用 javac 来编译 QueryDSL 生成的代码,但它找不到任何类。 都有最新的稳定版和最新的 Spring Boot 快照。 就我调试它而言,似乎 Spring Boot 的类加载器将其类路径公开为 URL 列表,但尝试将其传递给 javac 调用的 QueryDSL 代码以错误的方式解析它,因为它期望路径列表。 尚不确定这是否是 QueryDSL 或 Spring Boot 中的错误...
关于 QueryDSL 最近写项目,使用到了 Jpa 这个 ORM 规范支持,使用注解的方式实现 Sql ,但是用过 Jpa 的同学都知道 Jpa 对于单表操作很灵活,但是对于复杂一些的 SQL 就是很不友好了,所以这个地方我们就用到了 QueryDSL 来实现复杂的 Sql(另外强行安利一波 Tk-MyBatis) 什么是 QueryDSL ? QueryDSL仅仅是一...
querydsl-jpa 是一个基于 Java 语言的开源 ORM 查询框架,它提供了一种类型安全、流畅的 API 接口,使得查询 JPA 实体变得更加容易和简单。通过使用 querydsl-jpa,开发人员可以避免常见的 JPA 查询繁琐和容易出错的情况,同时,也可以享受到类型安全、易于维护和更加高效的查询体验。 querydsl-jpa 的主要特点包括: 1. 类型安全的查询:querydsl-jpa 提供了一种类型安全的查询 API 接口,完全避免了使用字符串拼接的方式来生成 SQL 语句的情况。 2. 支持 JPA 实体:querydsl-jpa 能够直接与 JPA 实体进行交互,从而使得在查询中使用的实体更加类型化和直观。 3. 支持复杂查询操作:querydsl-jpa 支持诸如嵌套子查询、联合查询、分页查询、排序查询等常见的查询操作,从而满足了更加复杂的查询需求。 4. 提供完整的类型支持:querydsl-jpa 支持传统的 SQL 数据类型,例如 INTEGER、VARCHAR 等,也支持 JPA 支持的所有类型,例如 Date、Time、Timestamp、Boolean 等。 5. 可维护性强:querydsl-jpa 生成的查询语句易于阅读和维护,从而减少了因为 SQL 语句难以阅读和理解而带来的错误和困难。 综上所述,querydsl-jpa 是一种高效、易用、类型安全、并且具有完整类型支持的 ORM 查询框架,它极大地方便了 Java 开发人员进行 JPA 实体查询操作,提高了项目的开发效率和质量。
如果想让ApiBoot Logging在控制台输出日志信息,需要修改application.yml配置文件内的日志等级,如下所示: #控制台输出日志 api.boot.logging.show-console-log=true #控制台日志级别 api.boot.logging.level.org.minbox.framework.api.boot.plugin.logging=info #实现美化打印请求日志 api.boot.logging.format-console-log-json=true 将OpenStreetMap导出的OSM数据导入MySQL数据库 刚上路DE小白: 建表语句下载不了啊,可否发我一下:654295097@qq.com谢谢啦! Grace:优雅高效的的记录业务操作日志 fizzlx: 问一下大佬的sample是删除了嘛 Grace:优雅高效的的记录业务操作日志 恒宇少年: https://github.com/minbox-projects/grace-sample