├── src ├── main │ ├── java │ │ └── io │ │ │ └── springboot │ │ │ └── example │ │ │ ├── service │ │ │ ├── UserService.java │ │ │ ├── DepartmentService.java │ │ │ ├── BaseService.java │ │ │ └── AbstractService.java │ │ │ ├── repository │ │ │ ├── UserRepository.java │ │ │ ├── DepartmentRepository.java │ │ │ └── BaseRepository.java │ │ │ ├── ExampleApplication.java │ │ │ └── entity │ │ │ ├── Department.java │ │ │ └── User.java │ └── resources │ │ └── application.yaml └── test │ └── java │ └── io │ └── springboot │ └── example │ └── test │ ├── Example.java │ ├── Example7.java │ ├── Example10.java │ ├── Example5.java │ ├── Example6.java │ ├── Example9.java │ ├── DataInit.java │ ├── Example1.java │ ├── Example8.java │ ├── Example3.java │ ├── Example2.java │ └── Example4.java ├── .gitignore ├── README.md └── pom.xml /src/main/java/io/springboot/example/service/UserService.java: -------------------------------------------------------------------------------- 1 | package io.springboot.example.service; 2 | 3 | import org.springframework.stereotype.Service; 4 | 5 | import io.springboot.example.entity.User; 6 | 7 | @Service 8 | public class UserService extends AbstractService { 9 | 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/io/springboot/example/repository/UserRepository.java: -------------------------------------------------------------------------------- 1 | package io.springboot.example.repository; 2 | 3 | import org.springframework.stereotype.Repository; 4 | 5 | import io.springboot.example.entity.User; 6 | 7 | @Repository 8 | public interface UserRepository extends BaseRepository { 9 | 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/io/springboot/example/service/DepartmentService.java: -------------------------------------------------------------------------------- 1 | package io.springboot.example.service; 2 | 3 | import org.springframework.stereotype.Service; 4 | 5 | import io.springboot.example.entity.Department; 6 | 7 | @Service 8 | public class DepartmentService extends AbstractService { 9 | 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/io/springboot/example/repository/DepartmentRepository.java: -------------------------------------------------------------------------------- 1 | package io.springboot.example.repository; 2 | 3 | import org.springframework.stereotype.Repository; 4 | 5 | import io.springboot.example.entity.Department; 6 | 7 | @Repository 8 | public interface DepartmentRepository extends BaseRepository { 9 | 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/io/springboot/example/service/BaseService.java: -------------------------------------------------------------------------------- 1 | package io.springboot.example.service; 2 | 3 | import org.springframework.data.jpa.repository.JpaRepository; 4 | import org.springframework.data.jpa.repository.JpaSpecificationExecutor; 5 | import org.springframework.data.querydsl.QuerydslPredicateExecutor; 6 | 7 | public interface BaseService extends JpaRepository, JpaSpecificationExecutor , QuerydslPredicateExecutor { 8 | 9 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | target/ 3 | !.mvn/wrapper/maven-wrapper.jar 4 | !**/src/main/** 5 | !**/src/test/** 6 | 7 | ### STS ### 8 | .apt_generated 9 | .classpath 10 | .factorypath 11 | .project 12 | .settings 13 | .springBeans 14 | .sts4-cache 15 | 16 | ### IntelliJ IDEA ### 17 | .idea 18 | *.iws 19 | *.iml 20 | *.ipr 21 | 22 | ### NetBeans ### 23 | /nbproject/private/ 24 | /nbbuild/ 25 | /dist/ 26 | /nbdist/ 27 | /.nb-gradle/ 28 | build/ 29 | 30 | ### VS Code ### 31 | .vscode/ -------------------------------------------------------------------------------- /src/main/java/io/springboot/example/repository/BaseRepository.java: -------------------------------------------------------------------------------- 1 | package io.springboot.example.repository; 2 | 3 | import org.springframework.data.jpa.repository.JpaRepository; 4 | import org.springframework.data.jpa.repository.JpaSpecificationExecutor; 5 | import org.springframework.data.querydsl.QuerydslPredicateExecutor; 6 | import org.springframework.data.repository.NoRepositoryBean; 7 | 8 | @NoRepositoryBean 9 | public interface BaseRepository extends JpaRepository, JpaSpecificationExecutor , QuerydslPredicateExecutor { 10 | 11 | } 12 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # SpringBoot-QueryDsl-Example 3 | 4 | ## 软件版本 5 | 6 | - SpringBoot 2.6.1 7 | - Java 17 8 | - MYSQL 8.x 9 | 10 | > 需要手动创建数据库,系统启动会后自动创建数据表(包括索引)。 11 | 12 | ## Example代码 13 | 14 | 都在 `src/main/resources` 目录下 15 | 16 | 17 | - `DataInit` 初始化演示数据(最先执行) 18 | - `Example1` 单表的查询/编辑/删除 19 | - `Example2` join查询 20 | - `Example3` 分页/排序 21 | - `Example4` 条件列子查询/查询列子查询/exists子查询/count子查询 22 | - `Example5` 聚合查询 23 | - `Example6` 条件分组 24 | - `Example7` 加锁 25 | - `Exapmle8` 结果集封装 26 | - `Exapmle9` 结果列的一些操作。case/转换/null判断... 27 | - `Exapmle10` spring-data-jpa 的支持 28 | - TODO 29 | 30 | ## 讨论 31 | 32 | 可以在这个帖子,讨论相关问题 33 | 34 | [https://springboot.io/t/topic/4424](https://springboot.io/t/topic/4424) 35 | 36 | 37 | -------------------------------------------------------------------------------- /src/main/java/io/springboot/example/ExampleApplication.java: -------------------------------------------------------------------------------- 1 | package io.springboot.example; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.boot.autoconfigure.domain.EntityScan; 6 | import org.springframework.data.jpa.repository.config.EnableJpaRepositories; 7 | 8 | 9 | /** 10 | * 11 | * 12 | * 13 | * @author KevinBlandy 14 | * 15 | */ 16 | @EnableJpaRepositories(basePackages = { "io.springboot.example.repository" }) 17 | @EntityScan(basePackages = { "io.springboot.example.entity" }) 18 | @SpringBootApplication 19 | public class ExampleApplication { 20 | public static void main(String[] args) { 21 | SpringApplication.run(ExampleApplication.class, args); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/main/resources/application.yaml: -------------------------------------------------------------------------------- 1 | server: 2 | port: 80 3 | 4 | logging: 5 | level: 6 | "ROOT": DEBUG 7 | "org.hibernate.type.descriptor.sql.BasicBinder": TRACE 8 | 9 | spring: 10 | application: 11 | name: "SpringBoot QueryDsl Example" 12 | 13 | datasource: 14 | type: com.zaxxer.hikari.HikariDataSource 15 | driver-class-name: com.mysql.cj.jdbc.Driver 16 | url: jdbc:mysql://localhost:3306/demo?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&allowMultiQueries=true 17 | username: root 18 | password: root 19 | 20 | jpa: 21 | database-platform: org.hibernate.dialect.MySQL8Dialect 22 | show-sql: true 23 | open-in-view: false 24 | properties: 25 | "hibernate.format_sql": true 26 | hibernate: 27 | ddl-auto: update 28 | -------------------------------------------------------------------------------- /src/test/java/io/springboot/example/test/Example.java: -------------------------------------------------------------------------------- 1 | package io.springboot.example.test; 2 | 3 | import io.springboot.example.ExampleApplication; 4 | import lombok.extern.slf4j.Slf4j; 5 | 6 | import javax.transaction.Transactional; 7 | 8 | import org.junit.Test; 9 | import org.junit.runner.RunWith; 10 | import org.springframework.boot.test.context.SpringBootTest; 11 | import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; 12 | import org.springframework.test.annotation.Rollback; 13 | import org.springframework.test.context.junit4.SpringRunner; 14 | 15 | @Slf4j 16 | @RunWith(SpringRunner.class) 17 | @SpringBootTest(classes = ExampleApplication.class, webEnvironment = WebEnvironment.RANDOM_PORT) 18 | public class Example { 19 | 20 | @Test 21 | @Transactional 22 | @Rollback(false) 23 | public void test() { 24 | log.info(""); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/io/springboot/example/entity/Department.java: -------------------------------------------------------------------------------- 1 | package io.springboot.example.entity; 2 | 3 | import java.time.LocalDateTime; 4 | 5 | import javax.persistence.Column; 6 | import javax.persistence.Entity; 7 | import javax.persistence.GeneratedValue; 8 | import javax.persistence.GenerationType; 9 | import javax.persistence.Id; 10 | import javax.persistence.Table; 11 | import javax.persistence.UniqueConstraint; 12 | 13 | import lombok.AllArgsConstructor; 14 | import lombok.Builder; 15 | import lombok.Data; 16 | import lombok.NoArgsConstructor; 17 | import lombok.With; 18 | 19 | 20 | @Data 21 | @Builder 22 | @AllArgsConstructor 23 | @NoArgsConstructor 24 | @With 25 | 26 | @Entity 27 | @Table(name = "department", uniqueConstraints = { 28 | @UniqueConstraint(columnNames = "title", name = "title") 29 | }) 30 | @org.hibernate.annotations.Table(appliesTo = "department", comment = "部门") 31 | public class Department { 32 | 33 | @Id 34 | @Column(columnDefinition = "INT UNSIGNED COMMENT 'ID'") 35 | @GeneratedValue(strategy = GenerationType.IDENTITY) 36 | private Integer id; 37 | 38 | @Column(columnDefinition = "VARCHAR(50) COMMENT '名称'", nullable = false) 39 | private String title; 40 | 41 | @Column(columnDefinition = "VARCHAR(200) COMMENT '备注'") 42 | private String remark; 43 | 44 | @Column(columnDefinition = "TINYINT UNSIGNED COMMENT '是否启用。0:禁用,1:启用'", nullable = false) 45 | private Boolean enabled; 46 | 47 | @Column(columnDefinition = "TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间'", nullable = false) 48 | private LocalDateTime createAt; 49 | } 50 | -------------------------------------------------------------------------------- /src/test/java/io/springboot/example/test/Example7.java: -------------------------------------------------------------------------------- 1 | package io.springboot.example.test; 2 | 3 | import io.springboot.example.ExampleApplication; 4 | import io.springboot.example.entity.QUser; 5 | import io.springboot.example.service.UserService; 6 | 7 | import javax.persistence.LockModeType; 8 | import javax.transaction.Transactional; 9 | 10 | import org.junit.Test; 11 | import org.junit.runner.RunWith; 12 | import org.springframework.beans.factory.annotation.Autowired; 13 | import org.springframework.boot.test.context.SpringBootTest; 14 | import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; 15 | import org.springframework.test.annotation.Rollback; 16 | import org.springframework.test.context.junit4.SpringRunner; 17 | /** 18 | * 19 | * 加锁查询 20 | * @author KevinBlandy 21 | * 22 | */ 23 | @RunWith(SpringRunner.class) 24 | @SpringBootTest(classes = ExampleApplication.class, webEnvironment = WebEnvironment.RANDOM_PORT) 25 | public class Example7 { 26 | 27 | @Autowired 28 | private UserService service; 29 | 30 | /** 31 | * 共享锁/独占锁 32 | * 33 | * 通过 LockModeType 枚举来指定锁类型 34 | */ 35 | @Test 36 | @Transactional 37 | @Rollback(false) 38 | public void test() { 39 | service.applyReadOnly(query -> { 40 | query.select(QUser.user.id).from(QUser.user) 41 | .setLockMode(LockModeType.PESSIMISTIC_READ) 42 | .fetch(); 43 | 44 | query.select(QUser.user.id).from(QUser.user) 45 | .setLockMode(LockModeType.PESSIMISTIC_WRITE) 46 | .fetch(); 47 | return null; 48 | }); 49 | 50 | /* 51 | 52 | select 53 | user0_.id as col_0_0_ 54 | from 55 | user user0_ for share 56 | 57 | select 58 | user0_.id as col_0_0_ 59 | from 60 | user user0_ for update 61 | 62 | */ 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/main/java/io/springboot/example/entity/User.java: -------------------------------------------------------------------------------- 1 | package io.springboot.example.entity; 2 | 3 | import java.io.Serializable; 4 | import java.math.BigDecimal; 5 | import java.time.LocalDateTime; 6 | 7 | import javax.persistence.Column; 8 | import javax.persistence.Entity; 9 | import javax.persistence.EnumType; 10 | import javax.persistence.Enumerated; 11 | import javax.persistence.GeneratedValue; 12 | import javax.persistence.GenerationType; 13 | import javax.persistence.Id; 14 | import javax.persistence.Index; 15 | import javax.persistence.Table; 16 | import javax.persistence.UniqueConstraint; 17 | 18 | import lombok.AllArgsConstructor; 19 | import lombok.Builder; 20 | import lombok.Data; 21 | import lombok.NoArgsConstructor; 22 | import lombok.With; 23 | 24 | @Data 25 | @Builder 26 | @AllArgsConstructor 27 | @NoArgsConstructor 28 | @With 29 | 30 | @Entity 31 | @Table(name = "user", uniqueConstraints = { 32 | @UniqueConstraint(columnNames = "name", name = "name") 33 | }, indexes = { 34 | @Index(columnList = "department_id", name = "department_id") 35 | }) 36 | @org.hibernate.annotations.Table(appliesTo = "user", comment = "用户") 37 | public class User implements Serializable { 38 | 39 | /** 40 | * 41 | */ 42 | private static final long serialVersionUID = 1691873956126863400L; 43 | 44 | @Id 45 | @Column(columnDefinition = "INT UNSIGNED COMMENT 'ID'") 46 | @GeneratedValue(strategy = GenerationType.IDENTITY) 47 | private Integer id; 48 | 49 | @Column(columnDefinition = "VARCHAR(50) COMMENT '名字'", nullable = false) 50 | private String name; 51 | 52 | @Column(columnDefinition = "VARCHAR(10) COMMENT '性别'", nullable = false) 53 | @Enumerated(EnumType.STRING) 54 | private Gender gender; 55 | 56 | @Column(columnDefinition = "DECIMAL(10,2)COMMENT '账户余额'") 57 | private BigDecimal balance; 58 | 59 | @Column(name = "department_id", columnDefinition = "INT UNSIGNED COMMENT '部门ID'", nullable = false) 60 | private Integer departmentId; 61 | 62 | @Column(columnDefinition = "TINYINT UNSIGNED COMMENT '是否启用。0:禁用,1:启用'", nullable = false) 63 | private Boolean enabled; 64 | 65 | @Column(columnDefinition = "TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间'", nullable = false) 66 | private LocalDateTime createAt; 67 | 68 | @Column(columnDefinition = "TIMESTAMP DEFAULT NULL COMMENT '修改时间'") 69 | private LocalDateTime updateAt; 70 | 71 | public static enum Gender { 72 | MALE, // 男 73 | FEMALE // 女 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/test/java/io/springboot/example/test/Example10.java: -------------------------------------------------------------------------------- 1 | package io.springboot.example.test; 2 | 3 | import io.springboot.example.ExampleApplication; 4 | import io.springboot.example.entity.QUser; 5 | import io.springboot.example.entity.User; 6 | import io.springboot.example.service.UserService; 7 | import lombok.extern.slf4j.Slf4j; 8 | 9 | import javax.transaction.Transactional; 10 | 11 | import org.junit.Test; 12 | import org.junit.runner.RunWith; 13 | import org.springframework.beans.factory.annotation.Autowired; 14 | import org.springframework.boot.test.context.SpringBootTest; 15 | import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; 16 | import org.springframework.data.domain.Page; 17 | import org.springframework.data.domain.PageRequest; 18 | import org.springframework.data.domain.Sort; 19 | import org.springframework.test.annotation.Rollback; 20 | import org.springframework.test.context.junit4.SpringRunner; 21 | 22 | /** 23 | * 24 | * Spring-Data-Jpa 对QueryDsl的支持 25 | * @author KevinBlandy 26 | * 27 | */ 28 | @Slf4j 29 | @RunWith(SpringRunner.class) 30 | @SpringBootTest(classes = ExampleApplication.class, webEnvironment = WebEnvironment.RANDOM_PORT) 31 | public class Example10 { 32 | 33 | @Autowired 34 | private UserService userService; 35 | 36 | /** 37 | * 38 | * QuerydslPredicateExecutor 是spring-data提供的一个操作接口 39 | * Repository 接口实现 : QuerydslPredicateExecutor 就可以使用这些支持方法 40 | * 41 | * 可以自己查看源码学习 42 | */ 43 | @Test 44 | @Transactional 45 | @Rollback(false) 46 | public void test() { 47 | QUser qUser = QUser.user; 48 | 49 | // 根据条件检索一条记录 50 | this.userService.findOne(qUser.id.eq(1).and(qUser.createAt.isNotNull())); 51 | 52 | // 根据条件获取所有 53 | this.userService.findAll(qUser.enabled.eq(true)); 54 | 55 | // 条件查询 & 排序 56 | this.userService.findAll(qUser.enabled.eq(true), qUser.id.desc()); 57 | 58 | // 查询所有 & 排序 59 | this.userService.findAll(qUser.id.asc().nullsLast()); 60 | 61 | // 条件查询 & 分页 & 排序 62 | Page result = this.userService.findAll(qUser.id.in(1, 2, 3), PageRequest.of(0, 2, Sort.by(Sort.Order.asc("name")))); 63 | log.info("test result: count={}, list={}", result.getTotalElements(), result.getContent()); 64 | 65 | // 根据条件判断是否存在 66 | this.userService.exists(qUser.id.eq(1)); 67 | 68 | // TODO 这个方法还不咋熟悉,好像是响应式相关的 69 | this.userService.findBy(qUser.enabled.eq(true), query -> { 70 | return query.all(); 71 | }); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/test/java/io/springboot/example/test/Example5.java: -------------------------------------------------------------------------------- 1 | package io.springboot.example.test; 2 | 3 | import io.springboot.example.ExampleApplication; 4 | import io.springboot.example.entity.QDepartment; 5 | import io.springboot.example.entity.QUser; 6 | import io.springboot.example.service.UserService; 7 | import lombok.extern.slf4j.Slf4j; 8 | 9 | import javax.transaction.Transactional; 10 | 11 | import org.junit.Test; 12 | import org.junit.runner.RunWith; 13 | import org.springframework.beans.factory.annotation.Autowired; 14 | import org.springframework.boot.test.context.SpringBootTest; 15 | import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; 16 | import org.springframework.test.annotation.Rollback; 17 | import org.springframework.test.context.junit4.SpringRunner; 18 | /** 19 | * 20 | * 聚合查询 21 | * @author KevinBlandy 22 | * 23 | */ 24 | @Slf4j 25 | @RunWith(SpringRunner.class) 26 | @SpringBootTest(classes = ExampleApplication.class, webEnvironment = WebEnvironment.RANDOM_PORT) 27 | public class Example5 { 28 | 29 | @Autowired 30 | private UserService userService; 31 | 32 | @Test 33 | @Transactional 34 | @Rollback(false) 35 | public void test() { 36 | 37 | this.userService.applyReadOnly(query -> { 38 | QUser qUser = QUser.user; 39 | QDepartment qDepartment = QDepartment.department; 40 | 41 | query.select(qDepartment.id, qDepartment.title, 42 | qUser.id.count() // 查询用户数量 43 | ) 44 | .from(qDepartment) 45 | .innerJoin(qUser).on(qUser.departmentId.eq(qDepartment.id)) 46 | .groupBy(qDepartment.id, qDepartment.title) // groupBy 47 | .having(qDepartment.title.in("魏国", "蜀国")) // having 48 | .fetch() 49 | .stream() 50 | .forEach(tuple -> { 51 | log.info("test result: id={}, title={}, userCount={}" 52 | ,tuple.get(qDepartment.id) 53 | ,tuple.get(qDepartment.title) 54 | ,tuple.get(qUser.id.count()) 55 | ); 56 | }) 57 | ; 58 | 59 | return null; 60 | }); 61 | 62 | /* 63 | 64 | select 65 | department0_.id as col_0_0_, 66 | department0_.title as col_1_0_, 67 | count(user1_.id) as col_2_0_ 68 | from 69 | department department0_ 70 | inner join 71 | user user1_ 72 | on ( 73 | user1_.department_id=department0_.id 74 | ) 75 | group by 76 | department0_.id , 77 | department0_.title 78 | having 79 | department0_.title in ( 80 | ? , ? 81 | ) 82 | test result: id=2, title=蜀国, userCount=3 83 | test result: id=1, title=魏国, userCount=2 84 | */ 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /src/test/java/io/springboot/example/test/Example6.java: -------------------------------------------------------------------------------- 1 | package io.springboot.example.test; 2 | 3 | import io.springboot.example.ExampleApplication; 4 | import io.springboot.example.entity.QUser; 5 | import io.springboot.example.entity.User; 6 | import io.springboot.example.service.UserService; 7 | import lombok.extern.slf4j.Slf4j; 8 | 9 | import java.time.LocalDateTime; 10 | import java.util.List; 11 | 12 | import javax.transaction.Transactional; 13 | 14 | import org.junit.Test; 15 | import org.junit.runner.RunWith; 16 | import org.springframework.beans.factory.annotation.Autowired; 17 | import org.springframework.boot.test.context.SpringBootTest; 18 | import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; 19 | import org.springframework.test.annotation.Rollback; 20 | import org.springframework.test.context.junit4.SpringRunner; 21 | 22 | import com.querydsl.core.BooleanBuilder; 23 | 24 | @Slf4j 25 | @RunWith(SpringRunner.class) 26 | @SpringBootTest(classes = ExampleApplication.class, webEnvironment = WebEnvironment.RANDOM_PORT) 27 | public class Example6 { 28 | 29 | @Autowired 30 | private UserService service; 31 | 32 | /** 33 | * 条件分组 34 | */ 35 | @Test 36 | @Transactional 37 | @Rollback(false) 38 | public void test() { 39 | List result = this.service.applyReadOnly(query -> { 40 | 41 | QUser qUser = QUser.user; 42 | 43 | // 条件 44 | BooleanBuilder condition = new BooleanBuilder(); 45 | 46 | // 分组1 47 | BooleanBuilder group1 = new BooleanBuilder(qUser.name.eq("张飞").or(qUser.id.gt(1))); 48 | 49 | // 分组2 50 | BooleanBuilder group2 = new BooleanBuilder(qUser.createAt.before(LocalDateTime.now()).and(qUser.enabled.eq(true))); 51 | 52 | // 合并分组,关系是and 53 | condition.and(group1.and(group2)); 54 | 55 | return query.select(qUser).from(qUser).where(condition).fetch(); 56 | }); 57 | 58 | log.info("test result={}", result); 59 | /* 60 | select 61 | user0_.id as id1_1_, 62 | user0_.balance as balance2_1_, 63 | user0_.create_at as create_a3_1_, 64 | user0_.department_id as departme4_1_, 65 | user0_.enabled as enabled5_1_, 66 | user0_.gender as gender6_1_, 67 | user0_.name as name7_1_, 68 | user0_.update_at as update_a8_1_ 69 | from 70 | user user0_ 71 | where 72 | ( 73 | user0_.name=? 74 | or user0_.id>? 75 | ) 76 | and user0_.create_at result = userService.applyReadOnly(query -> { 48 | 49 | 50 | QUser qUser = QUser.user; 51 | 52 | qUser.gender.when(User.Gender.FEMALE).then(""); 53 | 54 | return query.select(qUser.id, 55 | 56 | qUser.name.upper(), // 字段转换为大写 57 | 58 | qUser.createAt.dayOfYear(), // 获取一年中的日 59 | 60 | new CaseBuilder().when(qUser.createAt.year().eq(2021)).then("2021创建的") 61 | .when(qUser.createAt.year().eq(2022)).then("2022创建的") 62 | .otherwise("不知道啥时候创建的"), // 根据 createAt 字段,做 case 判断 63 | 64 | 65 | qUser.gender.when(Gender.FEMALE).then("女的") 66 | .when(Gender.MALE).then("男的") 67 | .otherwise("未知的"), // 根据 gender 字段,做 case 判断 68 | 69 | qUser.updateAt.isNotNull().as("updated") // 是否有更新过 70 | ) 71 | .from(qUser) 72 | .fetch() 73 | ; 74 | }); 75 | log.info("test result: {}", result); 76 | 77 | /* 78 | 79 | select 80 | user0_.id as col_0_0_, 81 | upper(user0_.name) as col_1_0_, 82 | dayofyear(user0_.create_at) as col_2_0_, 83 | case 84 | when year(user0_.create_at)=? then ? 85 | when year(user0_.create_at)=? then ? 86 | else '不知道啥时候创建的' 87 | end as col_3_0_, 88 | case 89 | when user0_.gender=? then ? 90 | when user0_.gender=? then ? 91 | else '未知的' 92 | end as col_4_0_, 93 | user0_.update_at is not null as col_5_0_ 94 | from 95 | user user0_ 96 | test result: [[1, 曹操, 336, 2021创建的, 男的, false], [2, 许褚, 336, 2021创建的, 男的, false], [3, 刘备, 336, 2021创建的, 男的, false], [4, 关羽, 336, 2021创建的, 男的, false], [5, 张飞, 336, 2021创建的, 男的, false], [6, 孙权, 336, 2021创建的, 男的, false], [7, 孙尚香, 336, 2021创建的, 女的, false]] 97 | */ 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /src/test/java/io/springboot/example/test/DataInit.java: -------------------------------------------------------------------------------- 1 | package io.springboot.example.test; 2 | 3 | import io.springboot.example.ExampleApplication; 4 | import io.springboot.example.entity.Department; 5 | import io.springboot.example.entity.User; 6 | import io.springboot.example.service.DepartmentService; 7 | import io.springboot.example.service.UserService; 8 | 9 | import java.math.BigDecimal; 10 | import java.time.LocalDateTime; 11 | 12 | import javax.transaction.Transactional; 13 | 14 | import org.junit.Test; 15 | import org.junit.runner.RunWith; 16 | import org.springframework.beans.factory.annotation.Autowired; 17 | import org.springframework.boot.test.context.SpringBootTest; 18 | import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; 19 | import org.springframework.test.annotation.Rollback; 20 | import org.springframework.test.context.junit4.SpringRunner; 21 | 22 | /** 23 | * 24 | * 初始化一些数据 25 | * 26 | * @author KevinBlandy 27 | * 28 | */ 29 | @RunWith(SpringRunner.class) 30 | @SpringBootTest(classes = ExampleApplication.class, webEnvironment = WebEnvironment.RANDOM_PORT) 31 | public class DataInit { 32 | 33 | @Autowired 34 | private UserService userService; 35 | 36 | @Autowired 37 | private DepartmentService departmentService; 38 | 39 | @Test 40 | @Transactional 41 | @Rollback(false) 42 | public void test() { 43 | // 创建几个部门 44 | Department dept1 = Department.builder().title("魏国").createAt(LocalDateTime.now()).remark("曹魏控XX").enabled(true).build(); 45 | Department dept2 = Department.builder().title("蜀国").createAt(LocalDateTime.now()).remark("蜀汉全是X").enabled(true).build(); 46 | Department dept3 = Department.builder().title("吴国").createAt(LocalDateTime.now()).remark("孙吴爱XX").enabled(true).build(); 47 | 48 | this.departmentService.save(dept1); 49 | this.departmentService.save(dept2); 50 | this.departmentService.save(dept3); 51 | 52 | // 创建一些用户 53 | User u1 = User.builder().name("曹操").balance(BigDecimal.valueOf(22.5)).createAt(LocalDateTime.now()).gender(User.Gender.MALE).departmentId(dept1.getId()).enabled(true).build(); 54 | User u2 = User.builder().name("许褚").balance(BigDecimal.valueOf(15)).createAt(LocalDateTime.now()).gender(User.Gender.MALE).departmentId(dept1.getId()).enabled(true).build(); 55 | 56 | User u3 = User.builder().name("刘备").balance(BigDecimal.valueOf(24)).createAt(LocalDateTime.now()).gender(User.Gender.MALE).departmentId(dept2.getId()).enabled(true).build(); 57 | User u4 = User.builder().name("关羽").balance(BigDecimal.valueOf(100)).createAt(LocalDateTime.now()).gender(User.Gender.MALE).departmentId(dept2.getId()).enabled(true).build(); 58 | User u5 = User.builder().name("张飞").balance(BigDecimal.valueOf(9)).createAt(LocalDateTime.now()).gender(User.Gender.MALE).departmentId(dept2.getId()).enabled(true).build(); 59 | 60 | User u6 = User.builder().name("孙权").balance(BigDecimal.valueOf(12)).createAt(LocalDateTime.now()).gender(User.Gender.MALE).departmentId(dept3.getId()).enabled(true).build(); 61 | User u7 = User.builder().name("孙尚香").balance(BigDecimal.valueOf(54)).createAt(LocalDateTime.now()).gender(User.Gender.FEMALE).departmentId(dept3.getId()).enabled(true).build(); 62 | 63 | this.userService.save(u1); 64 | this.userService.save(u2); 65 | this.userService.save(u3); 66 | this.userService.save(u4); 67 | this.userService.save(u5); 68 | this.userService.save(u6); 69 | this.userService.save(u7); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 4 | 4.0.0 5 | io.springboot 6 | springboot-querydsl-example 7 | 0.0.1-SNAPSHOT 8 | 9 | 10 | org.springframework.boot 11 | spring-boot-starter-parent 12 | 2.6.1 13 | 14 | 15 | 16 | UTF-8 17 | UTF-8 18 | UTF-8 19 | 17 20 | 17 21 | 22 | true 23 | 24 | 1.1.3 25 | 26 | 27 | 28 | 29 | org.springframework.boot 30 | spring-boot-starter-test 31 | test 32 | 33 | 34 | org.junit.vintage 35 | junit-vintage-engine 36 | test 37 | 38 | 39 | org.springframework.boot 40 | spring-boot-starter-web 41 | 42 | 43 | org.springframework.boot 44 | spring-boot-starter-tomcat 45 | 46 | 47 | 48 | 49 | org.springframework.boot 50 | spring-boot-starter-undertow 51 | 52 | 53 | org.springframework.boot 54 | spring-boot-starter-data-jpa 55 | 56 | 57 | com.querydsl 58 | querydsl-jpa 59 | 60 | 61 | com.querydsl 62 | querydsl-apt 63 | provided 64 | 65 | 66 | com.zaxxer 67 | HikariCP 68 | 69 | 70 | mysql 71 | mysql-connector-java 72 | 73 | 74 | org.projectlombok 75 | lombok 76 | provided 77 | 78 | 79 | 80 | 81 | 82 | org.springframework.boot 83 | spring-boot-maven-plugin 84 | 85 | true 86 | 87 | 88 | 89 | com.mysema.maven 90 | apt-maven-plugin 91 | ${apt-maven-plugin.version} 92 | 93 | 94 | 95 | process 96 | 97 | 98 | target/generated-sources/java 99 | com.querydsl.apt.jpa.JPAAnnotationProcessor 100 | 101 | 102 | 103 | 104 | 105 | 106 | -------------------------------------------------------------------------------- /src/test/java/io/springboot/example/test/Example1.java: -------------------------------------------------------------------------------- 1 | package io.springboot.example.test; 2 | 3 | import io.springboot.example.ExampleApplication; 4 | import io.springboot.example.entity.QDepartment; 5 | import io.springboot.example.entity.QUser; 6 | import io.springboot.example.entity.User; 7 | import lombok.extern.slf4j.Slf4j; 8 | 9 | import java.time.LocalDateTime; 10 | 11 | import javax.persistence.EntityManager; 12 | import javax.persistence.PersistenceContext; 13 | import javax.transaction.Transactional; 14 | 15 | import org.junit.Test; 16 | import org.junit.runner.RunWith; 17 | import org.springframework.boot.test.context.SpringBootTest; 18 | import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; 19 | import org.springframework.test.annotation.Rollback; 20 | import org.springframework.test.context.junit4.SpringRunner; 21 | 22 | import com.querydsl.core.types.Projections; 23 | import com.querydsl.jpa.JPAExpressions; 24 | import com.querydsl.jpa.impl.JPAQueryFactory; 25 | 26 | 27 | /** 28 | * 29 | * 单表的查询/编辑/删除 30 | * @author KevinBlandy 31 | * 32 | */ 33 | 34 | @RunWith(SpringRunner.class) 35 | @SpringBootTest(classes = ExampleApplication.class, webEnvironment = WebEnvironment.RANDOM_PORT) 36 | @Slf4j 37 | public class Example1 { 38 | 39 | @PersistenceContext 40 | private EntityManager entityManager; 41 | 42 | 43 | /** 44 | * 基本查询 45 | */ 46 | @Test 47 | @Transactional 48 | @Rollback(false) 49 | public void test1() { 50 | JPAQueryFactory query = new JPAQueryFactory(this.entityManager); 51 | 52 | QUser qUser = QUser.user; // 生成的查询对象,可以理解为数据表 53 | 54 | User user = query.select(qUser).from(qUser).where(qUser.id.eq(1)).fetchOne(); // 查询唯一记录,如果结果不止一个则异常 55 | 56 | log.info("rest1 reuslt={}", user); 57 | } 58 | 59 | /** 60 | * 投影查询,仅仅查询指定的列 61 | */ 62 | @Test 63 | @Transactional 64 | @Rollback(false) 65 | public void test2() { 66 | JPAQueryFactory query = new JPAQueryFactory(this.entityManager); 67 | 68 | QUser qUser = QUser.user; 69 | 70 | /** 71 | * 通过 Projections.bean 来指定封装的结果对象,以及要查询的列。 72 | * 属性通过相同的 getter/setter 输入,如果属性名称不同,可以通过列的 as() 来修改 73 | */ 74 | User user = query.select( 75 | Projections.bean(User.class, qUser.id, qUser.enabled, 76 | qUser.createAt.as("updateAt")) // 这里把 create_at 列的值封装到结果对象的 updateAt 属性中 77 | ) 78 | .from(qUser).where(qUser.enabled.eq(true)) 79 | .fetchFirst(); // 查询第一条记录,会主动添加类似于 LIMIT 1 限制语句 80 | 81 | log.info("test2 result={}", user); 82 | 83 | /* 84 | 从SQL日志可以看出,仅仅查询了声明的列。非常的灵活。避免滥用 SELECT * 查询。 85 | select 86 | user0_.id as col_0_0_, 87 | user0_.enabled as col_1_0_, 88 | user0_.create_at as col_2_0_ 89 | from 90 | user user0_ 91 | where 92 | user0_.enabled=? limit ? 93 | 94 | test2 result=User(id=1, name=null, gender=null, balance=null, departmentId=null, enabled=true, createAt=null, updateAt=2021-12-01T21:39:02) 95 | */ 96 | } 97 | 98 | /** 99 | * 更新操作 100 | */ 101 | @Test 102 | @Transactional 103 | @Rollback(false) 104 | public void test3() { 105 | JPAQueryFactory query = new JPAQueryFactory(this.entityManager); 106 | 107 | QUser qUser = QUser.user; 108 | QDepartment qDepartment = QDepartment.department; 109 | 110 | long ret = query.update(qUser) 111 | .set(qUser.balance, qUser.balance.add(100)) // 自增 112 | .set(qUser.updateAt, LocalDateTime.now()) // 设置列值 113 | .setNull(qUser.updateAt) // 设置为null 114 | .set(qUser.departmentId, 115 | JPAExpressions.select(qDepartment.id).from(qDepartment).where(qDepartment.id.eq(qUser.id)) 116 | ) // 子查询赋值(这里完全了为了演示这么写的) 117 | .where(qUser.id.eq(1).and(qUser.enabled.eq(true))) 118 | .execute() 119 | ; 120 | log.info("test3 result={}", ret); 121 | 122 | /* 123 | SQL日志 124 | 125 | update 126 | user 127 | set 128 | balance=balance+?, 129 | update_at=?, 130 | department_id=(select 131 | department1_.id 132 | from 133 | department department1_ 134 | where 135 | department1_.id=user.id) 136 | where 137 | id=? 138 | and enabled=? 139 | test3 result=1 140 | */ 141 | } 142 | 143 | 144 | // 新增 ???? 145 | 146 | 147 | /** 148 | * 我发现QueryDsl好像没新增Api,所以新增用JPA的Save就行。 149 | */ 150 | } 151 | -------------------------------------------------------------------------------- /src/test/java/io/springboot/example/test/Example8.java: -------------------------------------------------------------------------------- 1 | package io.springboot.example.test; 2 | 3 | import io.springboot.example.ExampleApplication; 4 | import io.springboot.example.entity.Department; 5 | import io.springboot.example.entity.QDepartment; 6 | import io.springboot.example.entity.QUser; 7 | import io.springboot.example.entity.User; 8 | import io.springboot.example.service.UserService; 9 | import lombok.AllArgsConstructor; 10 | import lombok.Builder; 11 | import lombok.Data; 12 | import lombok.NoArgsConstructor; 13 | import lombok.With; 14 | import lombok.extern.slf4j.Slf4j; 15 | 16 | import java.util.List; 17 | 18 | import javax.transaction.Transactional; 19 | 20 | import org.junit.Test; 21 | import org.junit.runner.RunWith; 22 | import org.springframework.beans.factory.annotation.Autowired; 23 | import org.springframework.boot.test.context.SpringBootTest; 24 | import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; 25 | import org.springframework.test.annotation.Rollback; 26 | import org.springframework.test.context.junit4.SpringRunner; 27 | 28 | import com.querydsl.core.types.Projections; 29 | import com.querydsl.core.types.QBean; 30 | 31 | 32 | /** 33 | * 34 | * 结果集封装 35 | * 36 | * 核心是 Projections 类 37 | * 38 | * @author KevinBlandy 39 | * 40 | */ 41 | @Slf4j 42 | @RunWith(SpringRunner.class) 43 | @SpringBootTest(classes = ExampleApplication.class, webEnvironment = WebEnvironment.RANDOM_PORT) 44 | public class Example8 { 45 | 46 | @Autowired 47 | private UserService userService; 48 | 49 | @Data 50 | @Builder 51 | @With 52 | @NoArgsConstructor 53 | @AllArgsConstructor 54 | public static class UserDTO { 55 | private Integer id; 56 | private String name; 57 | private Department department; // 部门 58 | } 59 | 60 | /** 61 | * 62 | * 前面的一些案例,已经展示了不少封装方式。Tuple/Projections 等等。 63 | * 64 | * 封装为自定义的对象 65 | */ 66 | @Test 67 | @Transactional 68 | @Rollback(false) 69 | public void test() { 70 | List result = this.userService.applyReadOnly(query -> { 71 | 72 | QUser qUser = QUser.user; 73 | QDepartment qDepartment = QDepartment.department; 74 | 75 | // 检索用户的id和name,封装到 UserDTO 76 | QBean userQBean = Projections.fields(UserDTO.class, qUser.id, qUser.name); 77 | // 检索部门的id和title,封装到 Department 78 | QBean departmentQBean = Projections.fields(Department.class, qDepartment.id, qDepartment.title); 79 | 80 | return query.select( 81 | userQBean, 82 | departmentQBean 83 | ) 84 | .from(qUser) 85 | .leftJoin(qDepartment).on(qDepartment.id.eq(qUser.departmentId)) 86 | .fetch() 87 | .stream() 88 | .map(tuple -> { 89 | // 从 tuple 中获取到结果,封装到一个对象中 90 | return tuple.get(userQBean).withDepartment(tuple.get(departmentQBean)); 91 | }) 92 | .toList() 93 | ; 94 | }); 95 | 96 | log.info("test result: {}", result); 97 | 98 | /* 99 | 100 | select 101 | user0_.id as col_0_0_, 102 | user0_.name as col_1_0_, 103 | department1_.id as col_2_0_, 104 | department1_.title as col_3_0_ 105 | from 106 | user user0_ 107 | left outer join 108 | department department1_ 109 | on ( 110 | department1_.id=user0_.department_id 111 | ) 112 | test result: [Example8.UserDTO(id=1, name=曹操, department=Department(id=1, title=魏国, remark=null, enabled=null, createAt=null)), Example8.UserDTO(id=2, name=许褚, department=Department(id=1, title=魏国, remark=null, enabled=null, createAt=null)), Example8.UserDTO(id=3, name=刘备, department=Department(id=2, title=蜀国, remark=null, enabled=null, createAt=null)), Example8.UserDTO(id=4, name=关羽, department=Department(id=2, title=蜀国, remark=null, enabled=null, createAt=null)), Example8.UserDTO(id=5, name=张飞, department=Department(id=2, title=蜀国, remark=null, enabled=null, createAt=null)), Example8.UserDTO(id=6, name=孙权, department=Department(id=3, title=吴国, remark=null, enabled=null, createAt=null)), Example8.UserDTO(id=7, name=孙尚香, department=Department(id=3, title=吴国, remark=null, enabled=null, createAt=null))] 113 | */ 114 | } 115 | 116 | /** 117 | * Projections 的其他一些封装方式 118 | */ 119 | @SuppressWarnings("unchecked") 120 | public void test2 () { 121 | 122 | // 根据构造函数封装 123 | QUser qUser = QUser.user; 124 | Projections.constructor(User.class, qUser.id, qUser.name); 125 | 126 | // 封装为map 127 | Projections.map(qUser.id, qUser.name); 128 | 129 | // 多个相同类型的列, 封装为数组 130 | Projections.array(Integer[].class, qUser.id, qUser.departmentId); 131 | 132 | //.... 自己研究吧 133 | } 134 | 135 | /** 136 | * 结果集分组 137 | * 在一些一对一多的检索下,可以对结果集进行分组。 138 | * QueryDsl提供了 groupBy Api,但是我不会。(我一般都是检索出结果后,用java的stream来完成) 139 | * 可以参考官方Demo: https://github.com/querydsl/querydsl/blob/master/querydsl-collections/src/test/java/com/querydsl/collections/GroupByTest.java 140 | * 141 | */ 142 | public void test3 () { 143 | this.userService.applyReadOnly(query -> { 144 | return query.select(QUser.user) 145 | .from(QUser.user) 146 | .transform(null) // 对结果集进行分组的函数 147 | ; 148 | }); 149 | } 150 | } 151 | -------------------------------------------------------------------------------- /src/test/java/io/springboot/example/test/Example3.java: -------------------------------------------------------------------------------- 1 | package io.springboot.example.test; 2 | 3 | import io.springboot.example.ExampleApplication; 4 | import io.springboot.example.entity.QUser; 5 | import io.springboot.example.entity.User; 6 | import io.springboot.example.service.UserService; 7 | import lombok.extern.slf4j.Slf4j; 8 | 9 | import java.util.List; 10 | 11 | import javax.transaction.Transactional; 12 | 13 | import org.junit.Test; 14 | import org.junit.runner.RunWith; 15 | import org.springframework.beans.factory.annotation.Autowired; 16 | import org.springframework.boot.test.context.SpringBootTest; 17 | import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; 18 | import org.springframework.test.annotation.Rollback; 19 | import org.springframework.test.context.junit4.SpringRunner; 20 | 21 | import com.querydsl.core.QueryResults; 22 | 23 | @Slf4j 24 | @RunWith(SpringRunner.class) 25 | @SpringBootTest(classes = ExampleApplication.class, webEnvironment = WebEnvironment.RANDOM_PORT) 26 | public class Example3 { 27 | 28 | @Autowired 29 | private UserService userService; 30 | 31 | /** 32 | * 分页 + count检索 33 | */ 34 | @SuppressWarnings("deprecation") 35 | @Test 36 | @Transactional 37 | @Rollback(false) 38 | public void test1() { 39 | 40 | // 第1页,5条记录 41 | int page = 1; 42 | int size = 5; 43 | 44 | QueryResults result = this.userService.applyReadOnly(query -> { 45 | QUser qUser = QUser.user; 46 | return query.select(qUser) 47 | .from(qUser) 48 | // offset + limit 完成分页 49 | .offset((page - 1) * size) 50 | .limit(size) 51 | .fetchResults() // fetchResults 返回分页数据 + count检索数据 52 | ; 53 | }); 54 | 55 | log.info("test1: count={}", result.getTotal()); // long 56 | log.info("test1 list={}", result.getResults()); // List 57 | 58 | /* 59 | SQL日志 60 | select 61 | count(user0_.id) as col_0_0_ 62 | from 63 | user user0_ 64 | 65 | 66 | select 67 | user0_.id as id1_1_, 68 | user0_.balance as balance2_1_, 69 | user0_.create_at as create_a3_1_, 70 | user0_.department_id as departme4_1_, 71 | user0_.enabled as enabled5_1_, 72 | user0_.gender as gender6_1_, 73 | user0_.name as name7_1_, 74 | user0_.update_at as update_a8_1_ 75 | from 76 | user user0_ limit ? 77 | test1: count=7 78 | test1 list=[User(id=1, name=曹操, gender=MALE, balance=122.50, departmentId=1, enabled=true, createAt=2021-12-01T21:39:02, updateAt=2021-12-01T21:43:50), User(id=2, name=许褚, gender=MALE, balance=15.00, departmentId=1, enabled=true, createAt=2021-12-01T21:39:02, updateAt=null), User(id=3, name=刘备, gender=MALE, balance=24.00, departmentId=2, enabled=true, createAt=2021-12-01T21:39:02, updateAt=null), User(id=4, name=关羽, gender=MALE, balance=100.00, departmentId=2, enabled=true, createAt=2021-12-01T21:39:02, updateAt=null), User(id=5, name=张飞, gender=MALE, balance=9.00, departmentId=2, enabled=true, createAt=2021-12-01T21:39:02, updateAt=null)] 79 | */ 80 | } 81 | 82 | /** 83 | * 只分页,不检索总记录数量。并且排序 84 | */ 85 | @Test 86 | @Transactional 87 | @Rollback(false) 88 | public void test2 () { 89 | 90 | // 第1页,5条记录 91 | int page = 1; 92 | int size = 5; 93 | 94 | List result = this.userService.applyReadOnly(query -> { 95 | QUser qUser = QUser.user; 96 | return query.select(qUser) 97 | .from(qUser) 98 | // offset + limit 完成分页 99 | .offset((page - 1) * size) 100 | .limit(size) 101 | .orderBy(qUser.createAt.desc(), // 根据 createAt desc 排序 102 | qUser.departmentId.asc().nullsFirst()) // 再根据 departmentId asc 排序, null 排在前面 103 | .fetch() // fetch 返回分页数据 104 | ; 105 | }); 106 | 107 | log.info("test2 : {}", result); 108 | 109 | /* 110 | SQL日志 111 | select 112 | user0_.id as id1_1_, 113 | user0_.balance as balance2_1_, 114 | user0_.create_at as create_a3_1_, 115 | user0_.department_id as departme4_1_, 116 | user0_.enabled as enabled5_1_, 117 | user0_.gender as gender6_1_, 118 | user0_.name as name7_1_, 119 | user0_.update_at as update_a8_1_ 120 | from 121 | user user0_ 122 | order by 123 | user0_.create_at desc, 124 | case 125 | when user0_.department_id is null then 0 126 | else 1 127 | end, 128 | user0_.department_id asc limit ? 129 | 130 | 131 | test2 : [User(id=1, name=曹操, gender=MALE, balance=122.50, departmentId=1, enabled=true, createAt=2021-12-01T21:39:02, updateAt=2021-12-01T21:43:50), User(id=2, name=许褚, gender=MALE, balance=15.00, departmentId=1, enabled=true, createAt=2021-12-01T21:39:02, updateAt=null), User(id=3, name=刘备, gender=MALE, balance=24.00, departmentId=2, enabled=true, createAt=2021-12-01T21:39:02, updateAt=null), User(id=4, name=关羽, gender=MALE, balance=100.00, departmentId=2, enabled=true, createAt=2021-12-01T21:39:02, updateAt=null), User(id=5, name=张飞, gender=MALE, balance=9.00, departmentId=2, enabled=true, createAt=2021-12-01T21:39:02, updateAt=null)] 132 | */ 133 | } 134 | 135 | /** 136 | * 只检索总记录数量,不查询数据 137 | */ 138 | @Test 139 | @Transactional 140 | @Rollback(false) 141 | public void test3 () { 142 | 143 | @SuppressWarnings("deprecation") 144 | long count = this.userService.applyReadOnly(query -> { 145 | QUser qUser = QUser.user; 146 | return query.select(qUser) 147 | .from(qUser) 148 | .fetchCount() // fetchCount 返回总数量 149 | ; 150 | }); 151 | 152 | log.info("test3 : {}", count); 153 | 154 | /* 155 | select 156 | count(user0_.id) as col_0_0_ 157 | from 158 | user user0_ 159 | test3 : 7 160 | */ 161 | } 162 | 163 | /** 164 | * fetchCount 和 fetchResults 很方便,但是被标记为过时,是最近这个版本才设置的。 165 | * 是因为分页查询,只针对于简单的查询,对于group 查询可能会导致异常。 166 | * 你如果非要使用的话,那么group查询是在内存中完成的分页。 167 | * 所以官方给了过时的标识,但是你只要用在基本的简单查询中是没有问题的。 168 | */ 169 | } 170 | -------------------------------------------------------------------------------- /src/test/java/io/springboot/example/test/Example2.java: -------------------------------------------------------------------------------- 1 | package io.springboot.example.test; 2 | 3 | import io.springboot.example.ExampleApplication; 4 | import io.springboot.example.entity.Department; 5 | import io.springboot.example.entity.QDepartment; 6 | import io.springboot.example.entity.QUser; 7 | import io.springboot.example.entity.User; 8 | import io.springboot.example.service.UserService; 9 | import lombok.Data; 10 | import lombok.extern.slf4j.Slf4j; 11 | 12 | import java.time.LocalDateTime; 13 | import java.util.List; 14 | 15 | import javax.transaction.Transactional; 16 | 17 | import org.junit.Test; 18 | import org.junit.runner.RunWith; 19 | import org.springframework.beans.factory.annotation.Autowired; 20 | import org.springframework.boot.test.context.SpringBootTest; 21 | import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; 22 | import org.springframework.test.annotation.Rollback; 23 | import org.springframework.test.context.junit4.SpringRunner; 24 | 25 | import com.querydsl.core.Tuple; 26 | import com.querydsl.core.types.Projections; 27 | 28 | /** 29 | * 30 | * join检索 31 | * @author KevinBlandy 32 | * 33 | */ 34 | @RunWith(SpringRunner.class) 35 | @SpringBootTest(classes = ExampleApplication.class, webEnvironment = WebEnvironment.RANDOM_PORT) 36 | @Slf4j 37 | public class Example2 { 38 | 39 | @Autowired 40 | private UserService userService; // 为了方便,直接用 service 进行检索,它封装了 JAPQueryFactory 41 | 42 | 43 | /** 44 | * Join查询 45 | */ 46 | @Test 47 | @Transactional 48 | @Rollback(false) 49 | public void test1() { 50 | this.userService.applyReadOnly(query -> { 51 | QUser qUser = new QUser("u"); 52 | QDepartment qDepartment = new QDepartment("d"); 53 | 54 | List list = query.select( 55 | qUser, 56 | qDepartment) 57 | .from(qUser) 58 | .innerJoin(qDepartment).on(qDepartment.id.eq(qUser.departmentId)) 59 | // leftJoin ..都有,自己,慢慢试 60 | .where(qDepartment.enabled.eq(true) 61 | .and(qUser.id.between(1, 3))) 62 | .fetch() // fetch 返回列表 63 | ; 64 | 65 | // tuple 本质上像是一个Map,可以获取每一列的数据 66 | 67 | list.forEach(tuple -> { 68 | User user = tuple.get(qUser); 69 | Department department = tuple.get(qDepartment); 70 | log.info("rest1 result: user={}, department={}", user, department); 71 | }); 72 | 73 | 74 | /* 75 | SQL 日志 76 | select 77 | user0_.id as id1_1_0_, 78 | department1_.id as id1_0_1_, 79 | user0_.balance as balance2_1_0_, 80 | user0_.create_at as create_a3_1_0_, 81 | user0_.department_id as departme4_1_0_, 82 | user0_.enabled as enabled5_1_0_, 83 | user0_.gender as gender6_1_0_, 84 | user0_.name as name7_1_0_, 85 | user0_.update_at as update_a8_1_0_, 86 | department1_.create_at as create_a2_0_1_, 87 | department1_.enabled as enabled3_0_1_, 88 | department1_.remark as remark4_0_1_, 89 | department1_.title as title5_0_1_ 90 | from 91 | user user0_ 92 | inner join 93 | department department1_ 94 | on ( 95 | department1_.id=user0_.department_id 96 | ) 97 | where 98 | department1_.enabled=? 99 | and ( 100 | user0_.id between ? and ? 101 | ) 102 | 103 | rest1 result: user=User(id=1, name=曹操, gender=MALE, balance=122.50, departmentId=1, enabled=true, createAt=2021-12-01T21:39:02, updateAt=2021-12-01T21:43:50), department=Department(id=1, title=魏国, remark=曹魏控XX, enabled=true, createAt=2021-12-01T21:39:02) 104 | rest1 result: user=User(id=2, name=许褚, gender=MALE, balance=15.00, departmentId=1, enabled=true, createAt=2021-12-01T21:39:02, updateAt=null), department=Department(id=1, title=魏国, remark=曹魏控XX, enabled=true, createAt=2021-12-01T21:39:02) 105 | rest1 result: user=User(id=3, name=刘备, gender=MALE, balance=24.00, departmentId=2, enabled=true, createAt=2021-12-01T21:39:02, updateAt=null), department=Department(id=2, title=蜀国, remark=蜀汉全是X, enabled=true, createAt=2021-12-01T21:39:02) 106 | */ 107 | 108 | return list; 109 | }); 110 | } 111 | 112 | // 自定义一个对象来接收数据 113 | @Data 114 | public static class UserDTO { 115 | private Integer id; 116 | private String name; 117 | private LocalDateTime createAt; 118 | private Integer departmentId; 119 | private String departmentTitle; 120 | } 121 | 122 | /** 123 | * Join投影查询 124 | */ 125 | @Test 126 | @Transactional 127 | @Rollback(false) 128 | public void test2() { 129 | 130 | List results = this.userService.applyReadOnly(query -> { 131 | 132 | QUser qUser = QUser.user; 133 | QDepartment qDepartment = QDepartment.department; 134 | 135 | return query.select( 136 | Projections.fields(UserDTO.class, // Projections.fields 根据字段属性名称封装数据 137 | qUser.id, qUser.name, qUser.createAt, // user 表的列 138 | qDepartment.id.as("departmentId"), qDepartment.title.as("departmentTitle") //department 表的列 139 | ) 140 | ) 141 | .from(qUser) 142 | .innerJoin(qDepartment).on(qDepartment.id.eq(qUser.departmentId)) 143 | .where(qUser.enabled.eq(true) 144 | .and(qDepartment.enabled.eq(true)) 145 | .and(qUser.id.in(1, 2, 3))) 146 | .orderBy(qUser.id.asc(), qUser.name.desc()) 147 | .fetch() 148 | ; 149 | }); 150 | 151 | log.info("test2 result={}", results); 152 | 153 | /* 154 | SQL日志 155 | select 156 | user0_.id as col_0_0_, 157 | user0_.name as col_1_0_, 158 | user0_.create_at as col_2_0_, 159 | department1_.id as col_3_0_, 160 | department1_.title as col_4_0_ 161 | from 162 | user user0_ 163 | inner join 164 | department department1_ 165 | on ( 166 | department1_.id=user0_.department_id 167 | ) 168 | where 169 | user0_.enabled=? 170 | and department1_.enabled=? 171 | and ( 172 | user0_.id in ( 173 | ? , ? , ? 174 | ) 175 | ) 176 | order by 177 | user0_.id asc, 178 | user0_.name desc 179 | 180 | test2 result=[Example2.UserDTO(id=1, name=曹操, createAt=2021-12-01T21:39:02, departmentId=1, departmentTitle=魏国), Example2.UserDTO(id=2, name=许褚, createAt=2021-12-01T21:39:02, departmentId=1, departmentTitle=魏国), Example2.UserDTO(id=3, name=刘备, createAt=2021-12-01T21:39:02, departmentId=2, departmentTitle=蜀国)] 181 | */ 182 | } 183 | } 184 | -------------------------------------------------------------------------------- /src/test/java/io/springboot/example/test/Example4.java: -------------------------------------------------------------------------------- 1 | package io.springboot.example.test; 2 | 3 | import io.springboot.example.ExampleApplication; 4 | import io.springboot.example.entity.QDepartment; 5 | import io.springboot.example.entity.QUser; 6 | import io.springboot.example.entity.User; 7 | import io.springboot.example.service.UserService; 8 | import lombok.extern.slf4j.Slf4j; 9 | 10 | import java.util.List; 11 | 12 | import javax.transaction.Transactional; 13 | 14 | import org.junit.Test; 15 | import org.junit.runner.RunWith; 16 | import org.springframework.beans.factory.annotation.Autowired; 17 | import org.springframework.boot.test.context.SpringBootTest; 18 | import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; 19 | import org.springframework.test.annotation.Rollback; 20 | import org.springframework.test.context.junit4.SpringRunner; 21 | 22 | import com.querydsl.core.Tuple; 23 | import com.querydsl.core.types.dsl.BooleanExpression; 24 | import com.querydsl.jpa.JPAExpressions; 25 | import com.querydsl.jpa.JPQLQuery; 26 | 27 | @Slf4j 28 | @RunWith(SpringRunner.class) 29 | @SpringBootTest(classes = ExampleApplication.class, webEnvironment = WebEnvironment.RANDOM_PORT) 30 | public class Example4 { 31 | 32 | @Autowired 33 | private UserService userService; 34 | 35 | /** 36 | * 条件中的单行单列子查询 37 | */ 38 | @Test 39 | @Transactional 40 | @Rollback(false) 41 | public void test() { 42 | List result = this.userService.applyReadOnly(query -> { 43 | QUser qUser = QUser.user; 44 | QDepartment qDepartment = QDepartment.department; 45 | 46 | return query.select(qUser) 47 | .from(qUser) 48 | .where(qUser.departmentId.eq( 49 | // 单行单列子查询 50 | JPAExpressions.select(qDepartment.id).from(qDepartment).where(qDepartment.title.eq("魏国")) 51 | )) 52 | .fetch() 53 | ; 54 | }); 55 | log.info("test result={}", result); 56 | 57 | /* 58 | select 59 | user0_.id as id1_1_, 60 | user0_.balance as balance2_1_, 61 | user0_.create_at as create_a3_1_, 62 | user0_.department_id as departme4_1_, 63 | user0_.enabled as enabled5_1_, 64 | user0_.gender as gender6_1_, 65 | user0_.name as name7_1_, 66 | user0_.update_at as update_a8_1_ 67 | from 68 | user user0_ 69 | where 70 | user0_.department_id=( 71 | select 72 | department1_.id 73 | from 74 | department department1_ 75 | where 76 | department1_.title=? 77 | ) 78 | 79 | test result=[User(id=1, name=曹操, gender=MALE, balance=22.50, departmentId=1, enabled=true, createAt=2021-12-02T08:59:43, updateAt=null), User(id=2, name=许褚, gender=MALE, balance=15.00, departmentId=1, enabled=true, createAt=2021-12-02T08:59:43, updateAt=null)] 80 | */ 81 | } 82 | 83 | /** 84 | * 条件中的单列多行子查询 85 | */ 86 | @Test 87 | @Transactional 88 | @Rollback(false) 89 | public void test1() { 90 | List result = this.userService.applyReadOnly(query -> { 91 | QUser qUser = QUser.user; 92 | QDepartment qDepartment = QDepartment.department; 93 | 94 | return query.select(qUser) 95 | .from(qUser) 96 | .where(qUser.departmentId.in( 97 | // 单行多列子查询 98 | JPAExpressions.select(qDepartment.id).from(qDepartment).where( 99 | qDepartment.title.eq("魏国").or(qDepartment.title.eq("吴国")) // 条件是 or ,会有2个结果 100 | ) 101 | )) 102 | .fetch() 103 | ; 104 | }); 105 | log.info("test1 result={}", result); 106 | 107 | /* 108 | select 109 | user0_.id as id1_1_, 110 | user0_.balance as balance2_1_, 111 | user0_.create_at as create_a3_1_, 112 | user0_.department_id as departme4_1_, 113 | user0_.enabled as enabled5_1_, 114 | user0_.gender as gender6_1_, 115 | user0_.name as name7_1_, 116 | user0_.update_at as update_a8_1_ 117 | from 118 | user user0_ 119 | where 120 | user0_.department_id in ( 121 | select 122 | department1_.id 123 | from 124 | department department1_ 125 | where 126 | department1_.title=? 127 | or department1_.title=? 128 | ) 129 | */ 130 | 131 | // test1 result=[User(id=6, name=孙权, gender=MALE, balance=12.00, departmentId=3, enabled=true, createAt=2021-12-02T08:59:43, updateAt=null), User(id=7, name=孙尚香, gender=FEMALE, balance=54.00, departmentId=3, enabled=true, createAt=2021-12-02T08:59:43, updateAt=null), User(id=1, name=曹操, gender=MALE, balance=22.50, departmentId=1, enabled=true, createAt=2021-12-02T08:59:43, updateAt=null), User(id=2, name=许褚, gender=MALE, balance=15.00, departmentId=1, enabled=true, createAt=2021-12-02T08:59:43, updateAt=null)] 132 | } 133 | 134 | /** 135 | * 结果集中的COUNT子查询 136 | */ 137 | @Test 138 | @Transactional 139 | @Rollback(false) 140 | public void test3() { 141 | List result = this.userService.applyReadOnly(query -> { 142 | QDepartment qDepartment = QDepartment.department; 143 | QUser qUser = QUser.user; 144 | 145 | // count 子查询 146 | JPQLQuery count = JPAExpressions.select(qUser.departmentId.count()).from(qUser).where(qUser.departmentId.eq(qDepartment.id)); 147 | 148 | return query.select(qDepartment.id, qDepartment.title, count) 149 | .from(qDepartment) 150 | .fetch() 151 | ; 152 | 153 | }); 154 | 155 | for (Tuple tuple : result) { 156 | // tuple 也可以通过下标和类型取值 157 | Integer id = tuple.get(0, Integer.class); 158 | String title = tuple.get(1, String.class); 159 | Long count = tuple.get(2, Long.class); 160 | log.info("tes3 result: id={}, title={}, count={}", id, title, count); 161 | } 162 | 163 | /* 164 | select 165 | department0_.id as col_0_0_, 166 | department0_.title as col_1_0_, 167 | (select 168 | count(user1_.department_id) 169 | from 170 | user user1_ 171 | where 172 | user1_.department_id=department0_.id) as col_2_0_ 173 | from 174 | department department0_ 175 | 176 | tes3 result: id=3, title=吴国, count=2 177 | tes3 result: id=2, title=蜀国, count=3 178 | tes3 result: id=1, title=魏国, count=2 179 | */ 180 | } 181 | 182 | /** 183 | * 结果集中的 EXISTS 子查询 184 | */ 185 | @Test 186 | @Transactional 187 | @Rollback(false) 188 | public void test4() { 189 | List result = this.userService.applyReadOnly(query -> { 190 | QDepartment qDepartment = QDepartment.department; 191 | QUser qUser = QUser.user; 192 | 193 | // exists 子查询 194 | BooleanExpression exists = JPAExpressions.selectOne() 195 | .from(qUser) 196 | .where(qUser.departmentId.eq(qDepartment.id) 197 | .and(qUser.gender.eq(User.Gender.FEMALE))) 198 | .exists(); 199 | 200 | return query.select( 201 | qDepartment.id, qDepartment.title, exists 202 | ) 203 | .from(qDepartment) 204 | .fetch() 205 | ; 206 | 207 | }); 208 | log.info("test4 result={}", result); 209 | 210 | /* 211 | select 212 | department0_.id as col_0_0_, 213 | department0_.title as col_1_0_, 214 | exists (select 215 | 1 216 | from 217 | user user1_ 218 | where 219 | user1_.department_id=department0_.id 220 | and user1_.gender=?) as col_2_0_ 221 | from 222 | department department0_ 223 | test4 result=[[3, 吴国, true], [2, 蜀国, false], [1, 魏国, false]] 224 | */ 225 | } 226 | } 227 | 228 | -------------------------------------------------------------------------------- /src/main/java/io/springboot/example/service/AbstractService.java: -------------------------------------------------------------------------------- 1 | package io.springboot.example.service; 2 | 3 | import java.util.List; 4 | import java.util.Optional; 5 | import java.util.function.Function; 6 | 7 | import javax.persistence.EntityManager; 8 | import javax.persistence.PersistenceContext; 9 | 10 | import org.springframework.beans.factory.annotation.Autowired; 11 | import org.springframework.data.domain.Example; 12 | import org.springframework.data.domain.Page; 13 | import org.springframework.data.domain.Pageable; 14 | import org.springframework.data.domain.Sort; 15 | import org.springframework.data.jpa.domain.Specification; 16 | import org.springframework.data.repository.query.FluentQuery.FetchableFluentQuery; 17 | //import org.springframework.data.repository.query.FluentQuery.FetchableFluentQuery; 18 | import org.springframework.transaction.annotation.Transactional; 19 | 20 | import com.querydsl.core.types.OrderSpecifier; 21 | import com.querydsl.core.types.Predicate; 22 | import com.querydsl.jpa.impl.JPAQueryFactory; 23 | 24 | import io.springboot.example.repository.BaseRepository; 25 | 26 | public class AbstractService implements BaseService { 27 | 28 | @Autowired 29 | protected BaseRepository baseRepository; 30 | 31 | @PersistenceContext 32 | protected EntityManager entityManager; 33 | 34 | @Override 35 | @Transactional(readOnly = true, rollbackFor = Throwable.class) 36 | public List findAll() { 37 | return this.baseRepository.findAll(); 38 | } 39 | 40 | @Override 41 | @Transactional(readOnly = true, rollbackFor = Throwable.class) 42 | public List findAll(Sort sort) { 43 | return this.baseRepository.findAll(sort); 44 | } 45 | 46 | @Override 47 | @Transactional(readOnly = true, rollbackFor = Throwable.class) 48 | public List findAllById(Iterable ids) { 49 | return this.baseRepository.findAllById(ids); 50 | } 51 | 52 | @Override 53 | @Transactional(rollbackFor = Throwable.class) 54 | public List saveAll(Iterable entities) { 55 | return this.baseRepository.saveAll(entities); 56 | } 57 | 58 | @Override 59 | @Transactional(rollbackFor = Throwable.class) 60 | public void flush() { 61 | this.baseRepository.flush(); 62 | } 63 | 64 | @Transactional(rollbackFor = Throwable.class) 65 | public S saveAndFlush(S entity) { 66 | return this.baseRepository.saveAndFlush(entity); 67 | } 68 | 69 | @Override 70 | @Transactional(rollbackFor = Throwable.class) 71 | @Deprecated 72 | public void deleteInBatch(Iterable entities) { 73 | this.baseRepository.deleteInBatch(entities); 74 | } 75 | 76 | @Override 77 | @Transactional(rollbackFor = Throwable.class) 78 | public void deleteAllInBatch() { 79 | this.baseRepository.deleteAllInBatch(); 80 | } 81 | 82 | @Override 83 | @Transactional(readOnly = true, rollbackFor = Throwable.class) 84 | @Deprecated 85 | public T getOne(ID id) { 86 | return this.baseRepository.getOne(id); 87 | } 88 | 89 | @Override 90 | @Transactional(readOnly = true, rollbackFor = Throwable.class) 91 | public List findAll(Example example) { 92 | return this.baseRepository.findAll(example); 93 | } 94 | 95 | @Override 96 | @Transactional(readOnly = true, rollbackFor = Throwable.class) 97 | public List findAll(Example example, Sort sort) { 98 | return this.baseRepository.findAll(example, sort); 99 | } 100 | 101 | @Override 102 | @Transactional(readOnly = true, rollbackFor = Throwable.class) 103 | public Page findAll(Pageable pageable) { 104 | return this.baseRepository.findAll(pageable); 105 | } 106 | 107 | @Override 108 | @Transactional(rollbackFor = Throwable.class) 109 | public S save(S entity) { 110 | return this.baseRepository.save(entity); 111 | } 112 | 113 | @Override 114 | @Transactional(readOnly = true, rollbackFor = Throwable.class) 115 | public Optional findById(ID id) { 116 | return this.baseRepository.findById(id); 117 | } 118 | 119 | @Override 120 | @Transactional(readOnly = true, rollbackFor = Throwable.class) 121 | public boolean existsById(ID id) { 122 | return this.baseRepository.existsById(id); 123 | } 124 | 125 | @Override 126 | @Transactional(readOnly = true, rollbackFor = Throwable.class) 127 | public long count() { 128 | return this.baseRepository.count(); 129 | } 130 | 131 | @Override 132 | @Transactional(rollbackFor = Throwable.class) 133 | public void deleteById(ID id) { 134 | this.baseRepository.deleteById(id); 135 | } 136 | 137 | @Override 138 | @Transactional(rollbackFor = Throwable.class) 139 | public void delete(T entity) { 140 | this.baseRepository.delete(entity); 141 | } 142 | 143 | @Override 144 | @Transactional(rollbackFor = Throwable.class) 145 | public void deleteAll(Iterable entities) { 146 | this.baseRepository.deleteAll(entities); 147 | } 148 | 149 | @Override 150 | @Transactional(rollbackFor = Throwable.class) 151 | public void deleteAll() { 152 | this.baseRepository.deleteAll(); 153 | } 154 | 155 | @Override 156 | @Transactional(readOnly = true, rollbackFor = Throwable.class) 157 | public Optional findOne(Example example) { 158 | return this.baseRepository.findOne(example); 159 | } 160 | 161 | @Override 162 | @Transactional(readOnly = true, rollbackFor = Throwable.class) 163 | public Page findAll(Example example, Pageable pageable) { 164 | return this.baseRepository.findAll(example, pageable); 165 | } 166 | 167 | @Override 168 | @Transactional(readOnly = true, rollbackFor = Throwable.class) 169 | public long count(Example example) { 170 | return this.baseRepository.count(example); 171 | } 172 | 173 | @Override 174 | @Transactional(readOnly = true, rollbackFor = Throwable.class) 175 | public boolean exists(Example example) { 176 | return this.baseRepository.exists(example); 177 | } 178 | 179 | @Override 180 | @Transactional(readOnly = true, rollbackFor = Throwable.class) 181 | public Optional findOne(Specification spec) { 182 | return this.baseRepository.findOne(spec); 183 | } 184 | 185 | @Override 186 | @Transactional(readOnly = true, rollbackFor = Throwable.class) 187 | public List findAll(Specification spec) { 188 | return this.baseRepository.findAll(spec); 189 | } 190 | 191 | @Override 192 | @Transactional(readOnly = true, rollbackFor = Throwable.class) 193 | public Page findAll(Specification spec, Pageable pageable) { 194 | return this.baseRepository.findAll(spec, pageable); 195 | } 196 | 197 | @Override 198 | @Transactional(readOnly = true, rollbackFor = Throwable.class) 199 | public List findAll(Specification spec, Sort sort) { 200 | return this.baseRepository.findAll(spec, sort); 201 | } 202 | 203 | @Override 204 | @Transactional(readOnly = true, rollbackFor = Throwable.class) 205 | public long count(Specification spec) { 206 | return this.baseRepository.count(spec); 207 | } 208 | 209 | @Override 210 | @Transactional(readOnly = true, rollbackFor = Throwable.class) 211 | public Optional findOne(Predicate predicate) { 212 | return this.baseRepository.findOne(predicate); 213 | } 214 | 215 | @Override 216 | @Transactional(readOnly = true, rollbackFor = Throwable.class) 217 | public Iterable findAll(Predicate predicate) { 218 | return this.baseRepository.findAll(predicate); 219 | } 220 | 221 | @Override 222 | @Transactional(readOnly = true, rollbackFor = Throwable.class) 223 | public Iterable findAll(Predicate predicate, Sort sort) { 224 | return this.baseRepository.findAll(predicate, sort); 225 | } 226 | 227 | @Override 228 | @Transactional(readOnly = true, rollbackFor = Throwable.class) 229 | public Iterable findAll(Predicate predicate, OrderSpecifier... orders) { 230 | return this.baseRepository.findAll(predicate, orders); 231 | } 232 | 233 | @Override 234 | @Transactional(readOnly = true, rollbackFor = Throwable.class) 235 | public Iterable findAll(OrderSpecifier... orders) { 236 | return this.baseRepository.findAll(orders); 237 | } 238 | 239 | @Override 240 | @Transactional(readOnly = true, rollbackFor = Throwable.class) 241 | public Page findAll(Predicate predicate, Pageable pageable) { 242 | return this.baseRepository.findAll(predicate, pageable); 243 | } 244 | 245 | @Override 246 | @Transactional(readOnly = true, rollbackFor = Throwable.class) 247 | public long count(Predicate predicate) { 248 | return this.baseRepository.count(predicate); 249 | } 250 | 251 | @Override 252 | @Transactional(readOnly = true, rollbackFor = Throwable.class) 253 | public boolean exists(Predicate predicate) { 254 | return this.baseRepository.exists(predicate); 255 | } 256 | 257 | @Override 258 | @Transactional(rollbackFor = Throwable.class) 259 | public List saveAllAndFlush(Iterable entities) { 260 | return this.baseRepository.saveAllAndFlush(entities); 261 | } 262 | 263 | @Override 264 | @Transactional(rollbackFor = Throwable.class) 265 | public void deleteAllInBatch(Iterable entities) { 266 | this.baseRepository.deleteAllInBatch(entities); 267 | } 268 | 269 | @Override 270 | @Transactional( rollbackFor = Throwable.class) 271 | public void deleteAllByIdInBatch(Iterable ids) { 272 | this.baseRepository.deleteAllByIdInBatch(ids); 273 | } 274 | 275 | @Override 276 | @Transactional(readOnly = true, rollbackFor = Throwable.class) 277 | public T getById(ID id) { 278 | return this.baseRepository.getById(id); 279 | } 280 | 281 | @Override 282 | @Transactional(rollbackFor = Throwable.class) 283 | public void deleteAllById(Iterable ids) { 284 | this.baseRepository.deleteAllById(ids); 285 | } 286 | 287 | @Override 288 | @Transactional(readOnly = true, rollbackFor = Throwable.class) 289 | public R findBy(Example example, Function, R> queryFunction) { 290 | return this.baseRepository.findBy(example, queryFunction); 291 | } 292 | 293 | @Override 294 | @Transactional(readOnly = true, rollbackFor = Throwable.class) 295 | public R findBy(Predicate predicate, Function, R> queryFunction) { 296 | return this.baseRepository.findBy(predicate, queryFunction); 297 | } 298 | 299 | // ----------------------- 300 | 301 | protected JPAQueryFactory newQuery() { 302 | return new JPAQueryFactory(this.entityManager); 303 | } 304 | 305 | @SuppressWarnings({ "unchecked", "hiding" }) 306 | protected T repository() { 307 | return (T) this.baseRepository; 308 | } 309 | 310 | 311 | @Transactional(rollbackFor = Throwable.class) 312 | public R apply(Function function) { 313 | return function.apply(this.newQuery()); 314 | } 315 | 316 | @Transactional(readOnly = true, rollbackFor = Throwable.class) 317 | public R applyReadOnly(Function function) { 318 | return function.apply(this.newQuery()); 319 | } 320 | } --------------------------------------------------------------------------------