最近看了下jpa与querydsl的用法,使用起来狠舒服,几乎不用写sql。
起因
- 过去一直都使用mybatis,想要尝试一下新花样
- 都是spring全家桶的东西,据说很爽
Start
1.Jpa
- 添加jpa的依赖
build.gradle
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| plugins { id 'org.springframework.boot' version '2.1.4.RELEASE' id 'java' }
apply plugin: 'io.spring.dependency-management'
group = 'com.dby.sail' version = '0.0.1' sourceCompatibility = '1.8'
repositories { mavenCentral() }
dependencies { compile 'org.springframework.boot:spring-boot-starter-data-jpa' compile 'org.springframework.boot:spring-boot-starter-web' compile 'mysql:mysql-connector-java:5.1.47' compile 'com.google.code.gson:gson:2.8.5' compile 'org.projectlombok:lombok:1.16.20' testCompile 'org.springframework.boot:spring-boot-starter-test' }
|
- 添加实体类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| package com.peihuan.demo;
import lombok.Data; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.Table; import java.util.Date;
@Data @Entity @Table(name = "course") public class Course { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private long id; private String title; private long length; private long teacherId; }
|
- 添加Repository
1 2 3
| public interface CourseRepository extends JpaRepository<Course, Long>{ Course findByTitleAndLength(String title,long lenth); }
|
我们的接口继承JpaRepository,泛型中,第一个是我们的实体类,第二个是主键类型。
同时,方法名必须满足一些规则,下图不完整,详情查看文档 spring-data-jpa
jpa中也提供了分页的操作,
1 2 3 4 5
| public interface CourseRepository extends JpaRepository<Course, Long> { Course findByTitleAndLength(String title,Long lenth); Page<Course> findAllByTeacherId(Long teacherId,Pageable pageable); }
|
到这里,jap就算结束了,在我们的service中注入CourseRepository就可以随意的调用增删改查了。
2.QueryDsl
jpa看起来很好用,为什么还需要QueryDsl呢?
因为jpa对以下场景不是特别友好:我想要查询Course,可以按title、length、teacherId查询。那么很容易写出这个接口 :
1
| Page<Course> findByTitleAndLengthAndTeacherId(String title,Long lenth,Long teacherId,Pageable pageable);
|
但实际上这三个参数,可能都会有,也可能都没有,也就是传null值。但如果你真的传了null值,那么会报错,因为jpa不允许空值。
那么该肿么办呢?一种情况是把所有情况的repository接口都写出来,一共 2 * 2 * 2 种情况,在service根据参数情况,调用相应的repository接口。但如果你有五六种查询条件,很明显是不可取的了……
QueryDsl久可以解决这种情况,并可以和jpa结合使用
- 首先修改我们的依赖:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
| plugins { id 'org.springframework.boot' version '2.1.4.RELEASE' id 'java' id "com.ewerk.gradle.plugins.querydsl" version "1.0.9" }
apply plugin: 'io.spring.dependency-management'
group = 'com.dby.sail' version = '0.0.1' sourceCompatibility = '1.8'
repositories { mavenCentral() }
/***start***/
def generatedSourcesDir = file("build/generated-sources/java")
sourceSets { main { java { srcDir "src/main/java" srcDir generatedSourcesDir } } }
querydsl { querydslDefault = true jpa = true querydslSourcesDir = generatedSourcesDir } /***end***/
dependencies { compile 'org.springframework.boot:spring-boot-starter-data-jpa' compile 'org.springframework.boot:spring-boot-starter-web' compile 'mysql:mysql-connector-java:5.1.47' compile 'com.google.code.gson:gson:2.8.5' compile("org.projectlombok:lombok:1.16.20") compile("com.querydsl:querydsl-core:4.2.1") compile("com.querydsl:querydsl-jpa:4.2.1") testCompile 'org.springframework.boot:spring-boot-starter-test' }
|
之后会发现多了个querydsl,不用管它,直接双击运行compileJava,会自动生成一些Q开头的文件,并不需要关心其内容。
之后尝试改写Repository
1 2 3 4 5 6 7 8
| public interface CourseRepository extends JpaRepository<Course,Long>, QuerydslPredicateExecutor<Channel>{ default Page<Course> findByTitleAndLength(String title,Long length,Pageable pageable) { QCourse qCourse = QCourse.ourse; BooleanExpression expression = qCourse.title.like("%" + title + "%") .and(qCourse.length.eq(length)); return findAll(expression, pageable); } }
|
测试后发现,这样也是错误的,参数也不能有空,那还有什么意义呢?但我们可以自己拼接BooleanExpression
1 2 3 4 5 6 7 8 9 10 11 12 13
| public interface CourseRepository extends JpaRepository<Course,Long>, QuerydslPredicateExecutor<Channel>{ default Page<Course> findByTitleAndLength(String title,Long length,Pageable pageable) { QCourse qCourse = QCourse.course; BooleanBuilder booleanBuilder = new BooleanBuilder(); if (StringUtils.hasText(title)) { booleanBuilder.and(qCourse.title.like("%" + title + "%")); } if (length != null) { booleanBuilder.and(qCourse.length.eq(length);); } return findAll(booleanBuilder, pageable); } }
|
这样就很美丽了,已经达到了我们的目标。
注意一个坑
由于高版本中的gradle使用的都是implementation,如果使用了它,那么会出现包无法找到的情况,所以必须使用compile和testCompile。