本篇的参考还挺大的,QueryDSL特别适合动态、复杂的表连接查询,基本不用写SQL了。
关于QueryDSL
最近写项目,使用到了 JPA 这个 ORM 规范支持,使用注解的方式实现 SQL,但是用过 JPA 的同学都知道 JPA 对于单表操作很灵活,但是对于复杂一些的 SQL 就是很不友好了,所以这个地方我们就用到了QueryDSL来实现复杂的SQL(另外强行安利一波 Tk-MyBatis)
什么是 QueryDSL ?
QueryDSL仅仅是一个通用的查询框架,专注于通过 JavaAPI 构建类型安全的 SQL 查询,也可以说 QueryDSL 是基于各种 ORM 框架以及 SQL 之上的一个通用的查询框架,QueryDSL 的查询,类是于 SQL 查询,很全面只不过一个是用 SQL 一个是用代码来代替 SQL。
不多了解 QueryDSL 的其他方面了,直接进入看配置和代码吧,毕竟博主也是刚刚接触这个查询框架,就不做过多的误导了。
说一下,下面示例的环境 -- MyBatis IDEA JPA QueryDSL
以下为项目操作(创建项目的操作就先省略掉了,这个应该都会,不会的可以去看博主的其他博客):
首先配置 pom.xml 更古不变的定律 T_T!! 对了再安利一个插件 lombok,配合 QueryDSL 可能会更好
<artifact>com.querydsl</artifact> querydsl-jpa com.querydsl querydsl-apt provided org.projectlombok lombok 1.16.10 provided
PS:lombok 可以已注解的方式来对代码进行简化,省去了 get 和 set 方法,至于怎么使用 lombok,先看本文示例吧
lombok是必须要导入的。
配置 application.properties 文件
server.port=8080 server.servlet.context-path=/ server.tomcat.uri-encoding=utf-8 ###添加 MySQL 数据库配置 spring.datasource.url=jdbc:mysql://127.0.0.1:3306/boot_test?serverTimezone=UTC&characterEncoding=UTF-8&useUnicode=true ###用户名 spring.datasource.username=xxx ###密码 spring.datasource.password=xxx ###驱动 spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver #是否自动生/更新成表,根据什么策略 spring.jpa.hibernate.ddl-auto=update #JPA配置 spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect spring.jpa.properties.hibernate.legacy_limit_handler=true #是否展示sql spring.jpa.show-sql= true
创建 entity 层,因为要先创建完实体类才可以去生成 QueryDSL
package com.cs.querydsl.model; import lombok.Data; import org.hibernate.annotations.GenericGenerator; import javax.persistence.*; /** * @ClassName:User * @Description:TODO User 实体类 * @Author LinLuoChen * @Date 2019/7/10/14:02 * @Version V1.0 **/ @Data // lombok 工具省去了 GET SET 方法 @Entity // 声明这个是一个实体类 @Table(name="user") // 对应的数据库的那个表 public class User { /** * @Description ID * @Author LinLuoChen * @Date 10:44 **/ @Id @GenericGenerator(name="id", strategy="uuid") // 这里我们的 ID 用的是 UUID @GeneratedValue(generator="id") private Integer id; /** * @Description 姓名 * @Author LinLuoChen * @Date 10:44 **/ @Column(name = "name") private String name; /** * @Description 密码 * @Author LinLuoChen * @Date 10:44 **/ @Column(name = "password") private String password; }
然后生成我们的Q实体类,第一步点击右侧 Maven 然后选择第一个文件夹,双击 compile 它会自动运行,运行成功后会生成一个 QUser 的实体类 ,因为我们的实体类叫做 User 他是根据我们实体类来生成的
开始编写 Dao 层,引入JPA 的接口 -- !!重要 !!!
package com.cs.querydsl.dao; import com.cs.querydsl.model.User; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaSpecificationExecutor; import org.springframework.data.repository.PagingAndSortingRepository; /** * @ClassName:UserDao * @Description:TODO 用来继承 Jpa 接口 * @Author LinLuoChen * @Date 2019/7/10/14:06 * @Version V1.0 **/ public interface UserDao extends JpaRepository<User, String>, JpaSpecificationExecutor, PagingAndSortingRepository<User, String> { // ----- }
这里我们省略 Service 层直接看 Impl 接口实现类,这里就先写一个单表查询进行测试
package com.cs.querydsl.service.impl; import com.cs.querydsl.dao.UserDao; import com.cs.querydsl.model.QUser; import com.cs.querydsl.model.User; import com.cs.querydsl.service.UserService; import com.querydsl.core.BooleanBuilder; import com.querydsl.core.types.Projections; import com.querydsl.jpa.impl.JPAQueryFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.thymeleaf.util.StringUtils; import javax.annotation.PostConstruct; import javax.persistence.EntityManager; import java.util.List; /** * @ClassName:UserServiceImpl * @Description:TODO 接口实现类 * @Author LinLuoChen * @Date 2019/7/10/14:09 * @Version V1.0 **/ @Service public class UserServiceImpl implements UserService { @Autowired UserDao userDao; @Autowired private EntityManager entityManager; //查询工厂实体 private JPAQueryFactory queryFactory; //实例化控制器完成后执行该方法实例化JPAQueryFactory @PostConstruct public void initFactory() { queryFactory = new JPAQueryFactory(entityManager); } /** * @Description 查询全部 * @Author LinLuoChen * @Date 10:53 * @return java.util.List **/ @Override public List findAll(User user) { // 使用 QueryDSL 进行查询 QUser qUser = QUser.user; // 定于获取条件 BooleanBuilder booleanBuilder = new BooleanBuilder(); // 要查询的条件 if(!StringUtils.isEmpty(user.getName())){ // 放入要查询的条件信息 booleanBuilder.and(qUser.name.contains(user.getName())); } // queryFactory 是上方定义的工厂实体 // select(生成的实体类的字段).from(生成实体类的名称).where(上方要查询的条件).orderBy(排序).fetch()进行查询 return queryFactory.select(qUser) .from(qUser) .where(booleanBuilder) .orderBy(qUser.name.desc()) .fetch(); } }
我们直接写一个测试类进行测试
package com.cs.querydsl; import com.cs.querydsl.model.User; import com.cs.querydsl.service.UserService; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; import java.util.List; @RunWith(SpringRunner.class) @SpringBootTest public class QuerydslApplicationTests { @Autowired UserService userService; @Test public void contextLoads() { } /** * @Description 测试查询全部方法 * @Author LinLuoChen * @Date 11:22 **/ @Test public void QueryDSLTest(){ User user = new User(); List list = userService.findAll(user); System.out.println(list); } }
测试结果,可以运行 ~~
虽然说 QueryDSL 也可以做增删改查,但是个人不建议使用(仅限单表),因为单表操作,其实使用 JPA 就可以了,包括 JPA 的动态查询,都是很适合单表的,不管是代码量还是效率个人感觉都比 QueryDSL 要快,尤其是代码量,少了不止一点半点,但是连表操作的话,就比较偏向于 QueryDSL 了,特别好用!!下边是连表操作的 QueryDSL ,另外说一下上边只是演示一下 QueryDSL 的使用方法,单表还是建议用 JPA 比较快!
---------------------------------------------------- 手动分界线 ----------------------------------------------------
package com.cs.querydsl.service.impl; import com.cs.querydsl.dao.LocDao; import com.cs.querydsl.model.Loc; import com.cs.querydsl.model.QLoc; import com.cs.querydsl.model.QUser; import com.cs.querydsl.service.LocService; import com.querydsl.core.BooleanBuilder; import com.querydsl.core.QueryResults; import com.querydsl.core.Tuple; import com.querydsl.jpa.impl.JPAQueryFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.thymeleaf.util.StringUtils; import javax.annotation.PostConstruct; import javax.persistence.EntityManager; import java.util.List; import java.util.stream.Collectors; /** * @ClassName:LocServiceImpl * @Description:TODO 接口实现类 * @Author LinLuoChen * @Date 2019/7/10/14:09 * @Version V1.0 **/ @Service public class LocServiceImpl implements LocService { @Autowired LocDao locDao; @Autowired private EntityManager entityManager; //查询工厂实体 private JPAQueryFactory queryFactory; //实例化控制器完成后执行该方法实例化JPAQueryFactory @PostConstruct public void initFactory() { queryFactory = new JPAQueryFactory(entityManager); } /** * @Description 查询全部 * @Author LinLuoChen * @Date 10:53 * @return java.util.List **/ @Override public List findAll(Loc loc) { // 使用 QueryDSL 进行查询 QLoc qLoc = QLoc.loc1; QUser qUser = QUser.user; // 定于获取条件 BooleanBuilder booleanBuilder = new BooleanBuilder(); // 要查询的条件 if(!StringUtils.isEmpty(loc.getLoc())){ // 放入要查询的条件信息 booleanBuilder.and(qLoc.loc.contains(loc.getLoc())); } //连接查询条件(Loc.id = User.id ) booleanBuilder.and(qLoc.id.eq(qUser.id)); // 使用 QueryDSL 进行多表联合查询 QueryResults listResult = queryFactory .select(QLoc.loc1,QUser.user) .from(qLoc, qUser)//查询两表 .where(booleanBuilder) .fetchResults(); //遍历 java8 自带流转换成集合 List collect = listResult.getResults().stream().map(tuple -> { Loc lcs = tuple.get(qLoc); return lcs; }).collect(Collectors.toList()); return collect; } }
查看结果
源码示例地址:https://download.csdn.net/download/qq_36537546/11356940
文章评论