這篇文章將為大家詳細(xì)講解有關(guān)QueryDSL如何在Spring JPA中使用,文章內(nèi)容質(zhì)量較高,因此小編分享給大家做個(gè)參考,希望大家閱讀完這篇文章后對(duì)相關(guān)知識(shí)有一定的了解。
員工經(jīng)過(guò)長(zhǎng)期磨合與沉淀,具備了協(xié)作精神,得以通過(guò)團(tuán)隊(duì)的力量開(kāi)發(fā)出優(yōu)質(zhì)的產(chǎn)品。創(chuàng)新互聯(lián)建站堅(jiān)持“專(zhuān)注、創(chuàng)新、易用”的產(chǎn)品理念,因?yàn)椤皩?zhuān)注所以專(zhuān)業(yè)、創(chuàng)新互聯(lián)網(wǎng)站所以易用所以簡(jiǎn)單”。公司專(zhuān)注于為企業(yè)提供成都做網(wǎng)站、網(wǎng)站制作、微信公眾號(hào)開(kāi)發(fā)、電商網(wǎng)站開(kāi)發(fā),小程序開(kāi)發(fā),軟件按需設(shè)計(jì)等一站式互聯(lián)網(wǎng)企業(yè)服務(wù)。
pom文件配置
QueryDSL
本身定位就是對(duì)某些技術(shù)的補(bǔ)充或者說(shuō)是完善,其提供了對(duì)JPA
、JDBC
、JDO
等技術(shù)的支持。這里引入的是QueryDSL-JPA
,需要注意一定要引入querydsl代碼生成器插件。
1.8 4.2.1 org.springframework.boot spring-boot-starter-data-jpa mysql mysql-connector-java 5.1.48 org.springframework.boot spring-boot-configuration-processor true org.projectlombok lombok true org.springframework.boot spring-boot-starter-test test org.junit.vintage junit-vintage-engine com.querydsl querydsl-jpa ${querydsl.version} org.springframework.boot spring-boot-maven-plugin com.mysema.maven apt-maven-plugin 1.1.3 com.querydsl querydsl-apt ${querydsl.version} process src/generated-sources/java/ com.querydsl.apt.jpa.JPAAnnotationProcessor
application配置文件
spring: datasource: ## 數(shù)據(jù)庫(kù)相關(guān)配置 url: jdbc:mysql://127.0.0.1:3306/example?useSSL=false username: root password: root driver-class-name: com.mysql.jdbc.Driver # 指定驅(qū)動(dòng)類(lèi) jpa: hibernate: ddl-auto: update # 自動(dòng)創(chuàng)建表以及更新表結(jié)構(gòu),生產(chǎn)環(huán)境慎用 show-sql: true # 打印執(zhí)行的SQL
配置類(lèi)
由于QueryDSL
不提供starter
,所以需要自行準(zhǔn)備一個(gè)配置類(lèi),代碼如下所示
import com.querydsl.jpa.impl.JPAQueryFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import javax.persistence.EntityManager; import javax.persistence.PersistenceContext; /** * QueryDSL配置類(lèi) * @author Null * @date 2019-10-24 */ @Configuration public class QuerydslConfig { @Autowired @PersistenceContext private EntityManager entityManager; @Bean public JPAQueryFactory queryFactory(){ return new JPAQueryFactory(entityManager); } }
啟動(dòng)類(lèi)
啟動(dòng)類(lèi)很簡(jiǎn)單,只需要使用@SpringBootApplication
即可
import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class QuerydslJpaDemoApplication { public static void main(String[] args) { SpringApplication.run(QuerydslJpaDemoApplication.class, args); } }
實(shí)體類(lèi)
主要有講師和課程,每個(gè)課程都有一個(gè)講師,每個(gè)講師有多個(gè)課程,即講師與課程的關(guān)系為一對(duì)多
課程
import lombok.Data; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; /** * 課程,一個(gè)課程對(duì)應(yīng)一個(gè)講師 * @author Null * @date 2019-10-24 */ @Data @Entity public class Course { /** * 課程ID */ @Id @GeneratedValue(strategy= GenerationType.IDENTITY) private Long id; /** * 課程名稱(chēng) */ private String name; /** * 對(duì)應(yīng)講師的ID */ private Long lecturerId; }
講師
import lombok.Data; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; /** * 講師,一個(gè)講師有多個(gè)課程 * @author Null * @date 2019-10-24 */ @Data @Entity public class Lecturer { /** * 講師ID */ @Id @GeneratedValue(strategy= GenerationType.IDENTITY) private Long id; /** * 講師名字 */ private String name; /** * 性別,true(1)為男性,false(0)為女性 */ private Boolean sex; }
Repository接口
如果要使用QuerDSL
需要Repository
接口除了繼承JpaRepository
接口(此接口為Spring-JPA
提供的接口)外,還需要繼承QuerydslPredicateExecutor
接口。關(guān)鍵示例如下:
課程Repository
import com.example.querydsl.jpa.entity.Course; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.querydsl.QuerydslPredicateExecutor; /** * 課程Repository * * @author Null * @date 2019-10-24 */ public interface CourseRepository extends JpaRepository, QuerydslPredicateExecutor { }
講師Repository
import com.example.querydsl.jpa.entity.Lecturer; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.querydsl.QuerydslPredicateExecutor; /** * 講師Repository * @author Null * @date 2019-10-24 */ public interface LecturerRepository extends JpaRepository, QuerydslPredicateExecutor { }
代碼生成
前面配置QueryDSL
代碼生成器就是用于這一步,==每次實(shí)體類(lèi)有變更最好重復(fù)執(zhí)行本步驟重新生成新的代碼==。由于個(gè)人習(xí)慣使用IDEA
,所以以IDEA
作為演示。
雙擊下圖內(nèi)容即可生成代碼了,
然后就會(huì)在src/generated-sources
目錄可以看到生成的代碼,包名與實(shí)體包名一致,但是類(lèi)名為Q
開(kāi)頭的文件
上一步的截圖我們可以看到其實(shí)生成的代碼被IDEA
識(shí)別為普通文件了,所以我們需要標(biāo)記src/generated-sources/java
目錄的用途,如下圖所示
標(biāo)記后,效果如下,可以看到代碼被正確識(shí)別了
到了這一步其實(shí)已經(jīng)完成整合了,下面就開(kāi)始驗(yàn)證是否正確整合以及展示QueryDSL
的優(yōu)勢(shì)了
驗(yàn)證整合與演示
下面我會(huì)使用單元測(cè)試來(lái)驗(yàn)證QueryDSL
是否正確整合以及演示一下QueryDSL
的優(yōu)勢(shì)
單元測(cè)試類(lèi)
這里主要是單元測(cè)試類(lèi)的關(guān)鍵內(nèi)容,需要注意@BeforeEach
是Junit5
的注解,表示每個(gè)單元測(cè)試用例執(zhí)行前會(huì)執(zhí)行的方法其實(shí)對(duì)應(yīng)Junit4
的@Before
/** * @SpringBootTest 默認(rèn)不支持事務(wù)且自動(dòng)回滾 * 使用@Transactional 開(kāi)啟事務(wù), * 使用@Rollback(false) 關(guān)閉自動(dòng)回滾 * @author Null * @date 2019-10-24 */ @SpringBootTest class QuerydslJpaDemoApplicationTests { @Autowired private CourseRepository courseRepository; @Autowired private LecturerRepository lecturerRepository; @Autowired private JPAQueryFactory queryFactory; /** * 初始化數(shù)據(jù) */ @BeforeEach public void initData(){ // 清空數(shù)據(jù)表 courseRepository.deleteAll(); lecturerRepository.deleteAll(); // 初始化講師 Lecturer tom=new Lecturer(); tom.setName("Tom"); tom.setSex(true); lecturerRepository.save(tom); Lecturer marry=new Lecturer(); marry.setName("Marry"); marry.setSex(false); lecturerRepository.save(marry); // 初始化課程 Course chinese=new Course(); chinese.setName("Chinese"); chinese.setLecturerId(tom.getId()); courseRepository.save(chinese); Course physics=new Course(); physics.setName("Physics"); physics.setLecturerId(tom.getId()); courseRepository.save(physics); Course english=new Course(); english.setName("English"); english.setLecturerId(marry.getId()); courseRepository.save(english); } ...省略各個(gè)用例 }
單表模糊查詢(xún)
/** * 根據(jù)課程名稱(chēng)模糊查詢(xún)課程 */ @Test public void testSelectCourseByNameLike() { // 組裝查詢(xún)條件 QCourse qCourse = QCourse.course; // %要自行組裝 BooleanExpression expression = qCourse.name.like("P%"); System.out.println(courseRepository.findAll(expression)); }
聯(lián)表查詢(xún)
/** * 根據(jù)講師姓名查課程 */ @Test public void testSelectCourseByLecturerName(){ QCourse qCourse = QCourse.course; QLecturer qLecturer = QLecturer.lecturer; // 這里包含了組裝查詢(xún)條件和執(zhí)行查詢(xún)的邏輯,組裝好條件后記得執(zhí)行fetch() Listcourses=queryFactory.select(qCourse) .from(qCourse) .leftJoin(qLecturer) .on(qCourse.lecturerId.eq(qLecturer.id)) .where(qLecturer.name.eq("Tom")) .fetch(); System.out.println(courses); }
更新
/** * 根據(jù)姓名更新講師性別
* 使用@Transactional開(kāi)啟事務(wù)
* 使用@Rollback(false)關(guān)閉自動(dòng)回滾
*/ @Test @Transactional @Rollback(false) public void testUpdateLecturerSexByName(){ QLecturer qLecturer = QLecturer.lecturer; // 更新Tom的性別為女性,返回的是影響記錄條數(shù) long num=queryFactory.update(qLecturer) .set(qLecturer.sex,false) .where(qLecturer.name.eq("Tom")) .execute(); // 這里輸出被更新的記錄數(shù) System.out.println(num); }
刪除
/** * 根據(jù)根據(jù)性別刪除講師 */ @Test @Transactional @Rollback(false) public void testDeleteLecturerBySex(){ QLecturer qLecturer = QLecturer.lecturer; // 刪除性別為男性的講師 long num=queryFactory.delete(qLecturer) .where(qLecturer.sex.eq(true)) .execute(); // 輸出被刪除的記錄數(shù) System.out.println(num); }
用例分析
從用例中可以看出其實(shí)QueryDSL
的API
更加切合原生的SQL
,基本上從代碼上就可以看出你希望執(zhí)行的SQL
了。
細(xì)心的朋友會(huì)發(fā)現(xiàn)QueryDSL
是沒(méi)有insert
方法,因?yàn)?code>JPA提供的save()
方法已經(jīng)足夠處理了。
同時(shí)要記得要組裝好你的SQL
后別忘記調(diào)用fetch()
或者execute()
方法。
總結(jié)
Spring Boot JPA
整合QueryDSL
的關(guān)鍵步驟
引入依賴(lài)和插件
編寫(xiě)配置類(lèi)
使用插件生成代碼
標(biāo)記生成文件為代碼
Repository繼承QuerydslPredicateExecutor
QueryDSL
的API
類(lèi)似原生SQL
,API
風(fēng)格類(lèi)似StringBuilder
的API
(Fluent API
風(fēng)格)。但是不提供insert
對(duì)應(yīng)的操作。
關(guān)于QueryDSL如何在Spring JPA中使用就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,可以學(xué)到更多知識(shí)。如果覺(jué)得文章不錯(cuò),可以把它分享出去讓更多的人看到。