上一篇介绍了入门基础篇SpringDataJPA访问数据库。本篇介绍SpringDataJPA进一步的定制化查询,使用JPQL或者SQL进行查询、部分字段映射、分页等。本文尽量以简单的建模与代码进行展示操作,文章比较长,包含查询的方方面面。如果能耐心看完这篇文章,你应该能使用SpringDataJPA应对大部分的持久层开发需求。如果你需要使用到动态条件查询,请查看下一篇博客,专题介绍SpringDataJPA的动态查询。
一、入门引导与准备
JPQL(JavaPersistence Query Language)是一种面向对象的查询语言,它在框架中最终会翻译成为sql进行查询,如果不知JPQL请大家自行谷歌了解一下,如果你会SQL,了解这个应该不废吹灰之力。
1.核心注解@Query介绍
使用SpringDataJPA进行JPQL/SQL一般查询的核心是@Query注解,我们先来看看该注解
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.METHOD, ElementType.ANNOTATION_TYPE })
@QueryAnnotation
@Documented
public @interface Query {
String value() default "";
String countQuery() default "";
String countProjection() default "";
boolean nativeQuery() default false;
String name() default "";
String countName() default "";
}
该注解使用的注解位置为方法、注解类型,一般我们用于注解方法即可。@QueryAnnotation标识这是一个查询注解;
@Query注解中有6个参数,value参数是我们需要填入的JPQL/SQL查询语句;nativeQuery参数是标识该查询是否为原生SQL查询,默认为false;countQuery参数为当你需要使用到分页查询时,可以自己定义(count查询)计数查询的语句,如果该项为空但是如果要用到分页,那么就使用默认的主sql条件来进行计数查询;name参数为命名查询需要使用到的参数,一般配配合@NamedQuery一起使用,这个在后面会说到;countName参数作用与countQuery相似,但是使用的是命名查询的(count查询)计数查询语句;countProjection为涉及到投影部分字段查询时的计数查询(count查询);关于投影查询,待会会说到。
有了@Query基础后,我们就可以小试牛刀一把了,对于jar包依赖,我们用的依旧是上一节的依赖,代码如下:
2.准备实验环境
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.4.1.RELEASE</version>
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>1.8</java.version>
<springBoot.groupId>org.springframework.boot</springBoot.groupId>
</properties>
<dependencies>
<!-- SpringBoot Start -->
<dependency>
<groupId>${springBoot.groupId}</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- jpa -->
<dependency>
<groupId>${springBoot.groupId}</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>${springBoot.groupId}</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
<!-- mysql -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
</dependencies>
项目结构如下:
JpaConfiguration配置类与上篇的相同:
@Order(Ordered.HIGHEST_PRECEDENCE)
@Configuration
@EnableTransactionManagement(proxyTargetClass=true)
@EnableJpaRepositories(basePackages={"org.fage.**.repository"})
@EntityScan(basePackages={"org.fage.**.entity"})
public class JpaConfiguration {
@Bean
PersistenceExceptionTranslationPostProcessor persistenceExceptionTranslationPostProcessor(){
return new PersistenceExceptionTranslationPostProcessor();
}
}
App类:
@SpringBootApplication
@ComponentScan("org.fage.**")
public class App {
public static void main(String[] args) throws Exception {
SpringApplication.run(App.class, args);
}
}
对于实体建模依旧用到上一篇所用的模型Department、User、Role,Department与User为一对多,User与Role为多对多,为了方便后面介绍投影,user多增加几个字段,代码如下:
@Entity
@Table(name = "user")
public class User implements Serializable {
private static final long serialVersionUID = -72