主题资源网站建设作业,北京工程质量建设协会网站,景山网站建设,网站建设公司前台参考文档#xff1a;SpringData JPA#xff1a;一文带你搞懂 - 知乎 (zhihu.com)
一、 前言
1.1 概述
Java持久化技术是Java开发中的重要组成部分#xff0c;它主要用于将对象数据持久化到数据库中#xff0c;以及从数据库中查询和恢复对象数据。在Java持久化技术领域SpringData JPA一文带你搞懂 - 知乎 (zhihu.com)
一、 前言
1.1 概述
Java持久化技术是Java开发中的重要组成部分它主要用于将对象数据持久化到数据库中以及从数据库中查询和恢复对象数据。在Java持久化技术领域Java Persistence API (JPA) 和 Spring Data JPA 是两个非常流行的框架。本文将对这两个框架进行简要介绍以帮助您更好地理解它们的作用和使用方法。
1.2 JPA简介
Java Persistence API (JPA) 是一种基于 ORM (Object-Relational Mapping) 技术的 Java EE 规范JPA是一种规范而不是具体的框架。它主要用于将 Java 对象映射到关系型数据库中以便于对数据进行持久化操作。
JPA 主要由三个部分组成分别是 Entity、EntityManager 和 Query。其中 Entity 用于描述 Java 对象和数据库表之间的映射关系EntityManager 用于管理实体对象的生命周期和完成实体对象与数据库之间的操作Query 用于查询数据。
JPA 支持多种底层实现如 Hibernate、EclipseLink 等。在使用时只需要引入相应的实现框架即可。 总结如下
JPAJava Persistence API是为Java EE平台设计的一种ORM解决方案。JPA提供了一些标准的API以及关系映射的元数据使得Java开发人员可以在没有具体SQL编程经验的情况下通过简单的注解配置实现对数据的访问和操作。JPA提供了对事务的支持允许Java开发人员进行基于POJO的开发在运行时将这些POJO映射成关系数据库表和列最大限度地减少了Java开发者与数据库的交互。
1.3 Spring Data JPA简介
Spring Data JPA 是 Spring 框架下的一个模块是基于 JPA 规范的上层封装旨在简化 JPA 的使用。
Spring Data JPA 提供了一些常用的接口如 JpaRepository、JpaSpecificationExecutor 等这些接口包含了很多常用的 CRUD 操作方法可直接继承使用。同时Spring Data JPA 还提供了基于方法命名规范的查询方式可以根据方法名自动生成相应的 SQL 语句并执行查询操作。这种方式可以大大减少编写 SQL 语句的工作量。
除了基础的 CRUD 操作外Spring Data JPA 还提供了一些高级功能如分页、排序、动态查询等。同时它也支持多种数据库如 MySQL、PostgreSQL、Oracle 等。 总结如下
Spring Data JPA 是 Spring Data 项目家族中的一员它为基于Spring框架应用程序提供了更加便捷和强大的数据操作方式。Spring Data JPA 支持多种数据存储技术包括关系型数据库和非关系型数据库。Spring Data JPA 提供了简单、一致且易于使用的API来访问和操作数据存储其中包括基本的CRUD操作、自定义查询方法、动态查询等功能。Spring Data JPA 也支持QueryDSL、Jinq、Kotlin Query等其他查询框架
二快速开始
2.1 配置环境
使用 Spring Data JPA 需要在项目中配置相关依赖项和数据源。Spring Data JPA 支持的数据库类型包括 MySQL、PostgreSQL、Oracle、MongoDB 等。
2.2 添加依赖
在项目的 pom.xml 文件中添加如下 Spring Data JPA 相关依赖
dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-data-jpa/artifactId
/dependency
dependencygroupIdmysql/groupIdartifactIdmysql-connector-java/artifactId
/dependency
如果使用其他数据库类型可以替换 mysql-connector-java 依赖并相应地调整数据源配置。
2.3 创建实体类
在项目中创建实体类用于映射数据库表和列。实体类需要使用 Entity 注解进行标记并且需要指定主键和自动生成策略Table可以指定该实体对应生成数据表的名称
Entity
Table(name user)
public class User {IdGeneratedValue(strategy GenerationType.IDENTITY)private Long id;private String name;// ...// 省略 getter 和 setter 方法
}
2.4 创建Repository接口
在项目中创建 Repository 接口用于定义数据访问方法。Repository 接口需要继承自 JpaRepository 接口并且需要使用 Repositor 注解进行标记例如
Repository
public interface UserRepository extends JpaRepositoryUser, Long {//自定义方法User findByName(String name);
}
在示例中我们定义了一个名为 UserRepository 的接口它继承自 JpaRepository 接口泛型参数分别为实体类型和主键类型并且新增了一个自定义查询方法 findByName。JpaRepository 接口包含了基本的增删改查方法且增和改都是调用save方法通过已存在id来判断 2.5 运行示例应用程序
编写示例代码并运行应用程序以验证 Spring Data JPA 的功能和使用方法。示例代码可以是简单的控制台程序也可以是 Web 应用程序。下面是一个基于 Spring Boot 的 Web 应用程序的示例代码
SpringBootApplication
public class Application implements CommandLineRunner {Autowiredprivate UserRepository userRepository;public static void main(String[] args) {SpringApplication.run(Application.class, args);}Overridepublic void run(String... args) throws Exception {User user new User();user.setName(Alice);user.setEmail(aliceexample.com);userRepository.save(user);User savedUser userRepository.findByName(Alice);System.out.println(savedUser);}
在示例代码中我们使用 SpringBootApplication 注解标记了应用程序入口类并且在 main 方法中启动了应用程序。CommandLineRunner 接口的 run 方法用于定义初始化逻辑在示例中我们创建了一个名为 Alice 的用户并将其保存到数据库中随后使用 findByName 方法查询并输出该用户信息。
三、实体映射
在使用 Spring Data JPA 时需要定义实体类和数据表之间的映射关系。下面介绍常用的实体映射注解。
3.1 Entity注解
Entity 注解用于标记实体类表示该类会被映射到数据库中的一个表。
示例代码
Entity
public class User {// 省略属性和方法
}
3.2 Table注解
Table 注解用于标注实体类与数据库表之间的映射关系并可以指定表的名称、唯一约束等信息。
示例代码
Entity
Table(name user)
public class User {// 省略属性和方法
}
3.3 Column注解
Column 注解用于标注实体类属性与数据表字段之间的映射关系并可以指定字段名称、长度、精度等信息。指定数据库列的长度和是否为null
示例代码
Entity
Table(name user)
public class User {Idprivate Long id;Column(name user_name, length 20, nullable false)private String userName;// 省略其他属性和方法
}
3.4 Id注解
Id 注解用于标注实体类属性作为主键通常与 GeneratedValue 注解一起使用指定主键生成策略。
示例代码
Entity
Table(name user)
public class User {IdGeneratedValue(strategy GenerationType.AUTO)private Long id;// 省略其他属性和方法
}
3.5 GeneratedValue注解
GeneratedValue 注解用于指定主键生成策略通常与 Id 注解一起使用。
示例代码
Entity
Table(name user)
public class User {IdGeneratedValue(strategy GenerationType.IDENTITY)private Long id;// 省略其他属性和方法
}
3.6 关系映射
关系映射通常包括一对一、一对多和多对多等关系。在 Spring Data JPA 中可以使用 OneToOne、OneToMany 和 ManyToMany 注解来标注关系映射。这些注解通常与 JoinColumn 注解一起使用用于指定关联的外键列。
示例代码
Entity
Table(name user)
public class User {IdGeneratedValue(strategy GenerationType.IDENTITY)private Long id;//一用户user对多 地址addressOneToMany(mappedBy user, cascade CascadeType.ALL)private ListAddress addresses;// 省略其他属性和方法
}Entity
Table(name address)
public class Address {IdGeneratedValue(strategy GenerationType.IDENTITY)private Long id;//多 地址address对一用户userManyToOneJoinColumn(name user_id)private User user;// 省略其他属性和方法
}
在上例中User 和 Address 之间是一对多的关系所以在 User 实体类中使用了 OneToMany 注解在 Address 实体类中使用了 ManyToOne 注解。mappedBy 属性用于指定关联的属性名称这里是 user表示 Address 实体类中的 user 属性与 User 实体类中的 addresses 属性相对应。cascade 属性表示级联操作这里使用 CascadeType.ALL 表示在删除 User 实体时同时删除其关联的所有 Address 实体。JoinColumn 注解用于指定外键名称这里是 user_id表示 Address 表中的 user_id 列与 User 表中的主键相对应。
四、Repository接口
Repository 接口是 Spring Data JPA 的核心接口之一它提供了基本的增删改查方法和自定义查询方法以及分页和排序等功能。在使用时需要继承 Repository 接口并指定对应的实体类和主键类型。
示例代码
public interface UserRepository extends RepositoryUser, Long {// 省略基本增删改查方法和自定义查询方法
}
4.1 各类Repository接口
4.1.1 增删改查方法接口Repository
在继承 Repository 接口后会默认提供基本的增删改查方法无需额外的代码实现即可使用。常用的方法如下
方法名描述T save(T entity)保存实体对象Iterable saveAll(Iterable entities)批量保存实体对象Optional findById(ID id)根据主键获取实体对象boolean existsById(ID id)判断是否存在特定主键的实体对象Iterable findAll()获取所有实体对象Iterable findAllById(Iterable ids)根据主键批量获取实体对象long count()获取实体对象的数量void deleteById(ID id)根据主键删除实体对象void delete(T entity)删除实体对象void deleteAll(Iterable? extends T entities)批量删除实体对象
示例代码
public interface UserRepository extends RepositoryUser, Long {// 保存用户User save(User user);// 根据主键获取用户OptionalUser findById(Long id);// 获取所有用户IterableUser findAll();// 根据主键删除用户void deleteById(Long id);
}
4.1.2 分页和基本查询接口JpaRepository
1特点 提供了基本的CRUD操作JpaRepository接口继承自PagingAndSortingRepository和CrudRepository接口因此提供了基本的CRUD操作包括保存、更新、删除、查询等。 支持分页和排序JpaRepository接口继承自PagingAndSortingRepository接口因此支持分页和排序功能可以方便地进行分页查询和结果排序。 自动生成查询方法JpaRepository接口支持使用方法名来自动生成查询方法无需手动编写SQL语句可以根据方法名的规则来自动生成查询方法。 提供了一些其他便利方法JpaRepository接口还提供了一些其他便利方法如批量操作、统计记录数等。
2父接口继承结构 4.1.3 动态查询接口JpaSpecificationExecutor
1介绍
JpaSpecificationExecutor接口定义了一些方法用于执行基于JPA规范的动态查询操作包括 T ListT findAll(SpecificationT spec)根据给定的Specification对象进行查询返回符合条件的实体对象列表。 T ListT findAll(SpecificationT spec, Sort sort)根据给定的Specification对象进行查询并按照指定的排序规则返回结果。 T PageT findAll(SpecificationT spec, Pageable pageable)根据给定的Specification对象进行分页查询返回符合条件的实体对象分页结果。
JpaSpecificationExecutor接口相对于JpaRepository接口提供了更加灵活、动态的查询功能适用于需要根据不同条件进行动态查询的场景。
2接口方法 3使用示例代码
//构造排序对象
Sort.Order showOrder Sort.Order.asc(order);
Sort sort Sort.by(showOrder);
String param something;
//拼接sql
PredicateBuilderDocumentationCategory predicateBuilder Specifications.or();
for (int i 0; i parentIds.length; i) {predicateBuilder predicateBuilder.like(name, % param %);
}
//创建查询条件对象
SpecificationDocumentationCategory specification predicateBuilder.build();
//执行查询
ListDocumentationCategory documentationCategoryList documentationCategoryRepository.findAll(specification, sort);
4.2 自定义查询方法
在 Repository 接口中可以定义自定义查询方法实现按照指定规则查询数据。Spring Data JPA 支持三种方式定义自定义查询方法方法名称查询、参数设置查询、使用 Query 注解查询。
4.2.1 示例代码
1文档表
Getter
Setter
NoArgsConstructor
EqualsAndHashCode(callSuper true)
public class Documentation extends AbstractBaseEntity {/*** 标题*/Column(name title, length 200, nullable false)private String title;/*** 单位*/Column(name unit, length 200)private String unit;/*** 文档类型DOCUMENTATION_TYPE*/Column(name doc_type, length 50)private String docType;/*** 年份*/Column(name year, length 4, nullable false)private String year;/*** 排序*/Column(name show_order)private Integer showOrder;/*** 是否置顶*/Column(name top_able, columnDefinition boolean default false)private Boolean top;/*** 是否上屏*/Column(name show_able, columnDefinition boolean default false)private Boolean show;/*** 文档资料目录*/ManyToOneJoinColumn(name document_category_id, nullable false)private DocumentationCategory documentCategory;/*** 文号*/Column(name document_number)private String documentNumber;/*** 文档来源*/ManyToOne(targetEntity Organization.class)JoinColumn(name document_source_id)//指定document_source_id字段为外键列private Organization organization;
}
对应的数据库
CREATE TABLE mt_rd_documentation (id bigint(20) NOT NULL,created_by bigint(20) DEFAULT NULL,created_time datetime NOT NULL,last_modified_by bigint(20) DEFAULT NULL,last_modified_time datetime NOT NULL,filter_path varchar(380) DEFAULT NULL,doc_type varchar(50) DEFAULT NULL,document_number varchar(255) DEFAULT NULL,is_html bit(1) DEFAULT b0,show_able bit(1) DEFAULT b0,show_order int(11) DEFAULT NULL,title varchar(200) NOT NULL,top_able bit(1) DEFAULT b0,unit varchar(200) DEFAULT NULL,year varchar(4) NOT NULL,content bigint(20) DEFAULT NULL,document_category_id bigint(20) NOT NULL,document_source_id bigint(20) DEFAULT NULL, #框架自动根据关系映射成bigint字段保存外键PRIMARY KEY (id),KEY idx_rd_documentation (title),KEY FKb8ucjiqbadllcx19p889x7iy8 (document_category_id),KEY FKhgiblpnx645pltghu1h5yy943 (document_source_id),CONSTRAINT FKb8ucjiqbadllcx19p889x7iy8 FOREIGN KEY (document_category_id) REFERENCES mt_rd_documentation_category (id),CONSTRAINT FKhgiblpnx645pltghu1h5yy943 FOREIGN KEY (document_source_id) REFERENCES mt_sys_organization (id)
) ENGINEInnoDB DEFAULT CHARSETutf8mb4;
2文件来源表单位表
public class Organization extends AbstractTreeEntityOrganization {ApiModelProperty(value 主键自动增长, 新建时为null,required true)ValueCopyIgnoreIdGeneratedValue(generator snowflake)GenericGenerator(name snowflake,strategy com.matech.framework.spring.jpa.SnowflakeIdGenerator)private Long id;Column(name name,length 100,nullable false)private String name;Column(name short_name,length 100,nullable false)private String shortName;Column(name organization_type,nullable false)Enumerated(EnumType.STRING)private OrganizationType organizationType;Column(name is_available,nullable false)private Boolean available true;ManyToMany(mappedBy organizations,fetch FetchType.LAZY)OrderBy(showOrder asc)private SetEmployee employees new LinkedHashSet();Transientprivate Unit unit;Transientprivate Department department;Transientprivate Position position;Column(name is_interior,nullable false)private Boolean interior true;ManyToMany(fetch FetchType.LAZY)JoinTable(name mt_sys_organization_role,joinColumns {JoinColumn(name organization_id
)},inverseJoinColumns {JoinColumn(name role_id
)})OrderBy(name asc)private SetRole roles new LinkedHashSet();Transientprivate String fullName;
} 3Query语句 下面Query中可以直接根据实体的对象成员的元素进行过滤框架通过根据JoinColumn配置的关系自动进行联表查询实现简化SQL开发的工作量使得程序员有更多的余力致力于业务代码的开发注意这个不是普通的SQL语句还需进过jpa框架解析的所以可以用实体的字段名 如果某些复杂的业务场景需要写《原生的SQL语句》这就需要在Query注解中指定nativeQuery true 参数该参数默认为false表示不使用原生SQL。值得注意的是采用原生SQL时不能直接指定返回一个包含子对象成员的对象结果 因为原生SQL不经过JPA框架处理返回对象成员时数据库保存的是该对象在数据库的id而实体对象成员需要的是一个对象会导致类型转换错误。但是某些场景可以直接返回例如返回对象成员都是基础数据类型等。
Repository
public interface DocumentationRepository extends JpaRepositoryDocumentation, Long, JpaSpecificationExecutorDocumentation {Query(select d.organization from Documentation d where d.organization.name 研发部)ListOrganization getAllOrg();Query(value select org.id from mt_rd_documentation d inner JOIN mt_sys_organization org on d.document_source_id org.id where org.name 研发部, nativeQuery true)ListLong getAllOrg2();
}4.2.1 方法名称查询 方法名称查询是 Spring Data JPA 中最简单的一种自定义查询方法并且不需要额外的注解或 XML 配置。它通过方法名来推断出查询的条件例如以 findBy 开头的方法表示按照某些条件查询以 deleteBy 开头的方法表示按照某些条件删除数据。
示例代码
public interface UserRepository extends RepositoryUser, Long {// 根据用户名查询用户User findByUserName(String userName);// 根据年龄查询用户列表ListUser findByAge(Integer age);// 根据用户名和密码查询用户User findByUserNameAndPassword(String userName, String password);// 根据主键和用户名删除用户void deleteByIdAndUserName(Long id, String userName);
}
4.2.2 查询参数设置 除了方法名称查询外还可以使用参数设置方式进行自定义查询。它通过在方法上使用 Query 注解来指定查询语句然后使用 Param 注解来指定方法参数与查询语句中的参数对应关系。
示例代码
public interface UserRepository extends RepositoryUser, Long {// 根据用户名查询用户Query(SELECT u FROM User u WHERE u.userName :userName)User findByUserName(Param(userName) String userName);// 根据用户名和密码查询用户Query(SELECT u FROM User u WHERE u.userName :userName AND u.password :password)User findByUserNameAndPassword(Param(userName) String userName, Param(password) String password);
}
4.2.3 使用Query注解 在自定义查询方法时还可以使用 Query 注解直接指定查询语句。Query 注解的 value 属性表示查询语句可以使用占位符 ?1、?2 等表示方法参数。
示例代码
public interface UserRepository extends RepositoryUser, Long {// 根据用户名查询用户Query(value SELECT * FROM user WHERE user_name ?1, nativeQuery true)User findByUserName(String userName);// 根据用户名和密码查询用户Query(value SELECT * FROM user WHERE user_name ?1 AND password ?2, nativeQuery true)User findByUserNameAndPassword(String userName, String password);
}
4.3 使用 Sort 和 Pageable 进行排序和分页
在查询数据时经常需要对结果进行排序和分页操作。Spring Data JPA 提供了 Sort 和 Pageable 两个类来实现排序和分页功能。
Sort 类表示排序规则可以使用 Sort.by() 静态方法创建实例并指定排序属性和排序方向。常用方法如下
方法名描述static Sort by(Sort.Order... orders)根据排序规则创建 Sort 实例static Sort.Order by(String property)根据属性升序排序static Sort.Order by(String property, Sort.Direction direction)根据属性排序
示例代码
public interface UserRepository extends RepositoryUser, Long {// 根据年龄升序查询用户列表ListUser findByOrderByAgeAsc();// 根据年龄降序分页查询用户列表PageUser findBy(Pageable pageable);
}
Pageable 类表示分页信息可以使用 PageRequest.of() 静态方法创建实例并指定页码、每页数据量和排序规则。常用方法如下
方法名描述static PageRequest of(int page, int size, Sort sort)创建分页信息实例static PageRequest of(int page, int size, Sort.Direction direction, String... properties)创建分页信息实例
示例代码
public interface UserRepository extends RepositoryUser, Long {// 根据年龄降序分页查询用户列表PageUser findBy(Pageable pageable);
}// 使用
Pageable pageable PageRequest.of(0, 10, Sort.by(age).descending());
PageUser page userRepository.findBy(pageable);
ListUser userList page.getContent();
4.4 使用 Modifying 注解进行修改
在 Spring Data JPA 中使用 update 和 delete 语句需要使用 Modifying 注解标注并且需要添加 Transactional 注解开启事务。需要注意的是Modifying 注解只支持 DML 语句。
示例代码
public interface UserRepository extends RepositoryUser, Long {// 更新用户密码ModifyingTransactionalQuery(UPDATE User u SET u.password :password WHERE u.id :id)void updatePasswordById(Param(id) Long id, Param(password) String password);// 删除年龄大于等于 age 的用户ModifyingTransactionalQuery(DELETE FROM User u WHERE u.age :age)void deleteByAgeGreaterThanEqual(Param(age) Integer age);
}
五、高级查询
5.1 使用 Specification 进行动态查询
在实际应用中我们经常需要根据条件动态生成查询语句。Spring Data JPA 提供了 Specification 接口来支持动态查询它可以通过使用匿名内部类或 Lambda 表达式来实现。
Specification 接口定义了 toPredicate() 方法该方法接受一个 RootT 对象和一个 CriteriaQuery? 对象作为参数并返回一个 Predicate 对象表示查询条件。
在 toPredicate() 方法内部可以通过 root.get() 方法获取实体属性并使用 criteriaBuilder 构建查询条件。 1.例如以下 Lambda 表达式表示查询 age 大于等于 18 的用户。
public interface UserRepository extends JpaRepositoryUser, Long, JpaSpecificationExecutorUser {ListUser findAll(SpecificationUser spec);
}// 使用
SpecificationUser spec (root, query, criteriaBuilder) - criteriaBuilder.greaterThanOrEqualTo(root.get(age), 18);
userRepostory.findAll(spec);
2.假设我们有一个 User 实体类该实体包含了 username、age 和 email 等属性。现在我们需要根据传入的参数动态生成查询条件并查询用户列表。
首先我们需要在 UserRepository 接口中继承 JpaSpecificationExecutor 接口示例代码如下
Repository
public interface UserRepository extends JpaRepositoryUser, Long, JpaSpecificationExecutorUser {}
然后我们可以在 UserService 中定义一个方法来进行动态查询示例代码如下
Service
public class UserServiceImpl implements UserService {Autowiredprivate UserRepository userRepository;Overridepublic ListUser findUsersByCondition(String username, String email, Integer age) {return userRepository.findAll((root, query, criteriaBuilder) - {ListPredicate list new ArrayList();if (StringUtils.isNotBlank(username)) {list.add(criteriaBuilder.equal(root.get(username), username));}if (StringUtils.isNotBlank(email)) {list.add(criteriaBuilder.like(root.get(email), % email %));}if (age ! null) {list.add(criteriaBuilder.greaterThanOrEqualTo(root.get(age), age));}Predicate[] predicates list.toArray(new Predicate[list.size()]);return criteriaBuilder.and(predicates);});}}
在上述代码中我们首先判断传入的 username、email、age 是否为空然后通过 Lambda 表达式的方式构造查询条件并将其作为参数传给 findAll 方法进行查询。在 Lambda 表达式中我们使用 CriteriaBuilder 来构造查询条件通过 root.get() 方法获取属性的值然后使用 equal()、like() 或者其他方法创建 Predicate 对象。最后我们将所有的 Predicate 组合起来返回结果。
5.2 使用 QueryDSL 进行复杂查询
QueryDSL 是一种流行的 Java 查询框架它以编程方式构建类型安全的查询。Spring Data JPA 支持 QueryDSL可以使用 QueryDSL 提供的 API 构建复杂的查询语句。
使用 QueryDSL 前需要添加依赖和配置。首先我们需要在 pom.xml 文件中添加以下依赖
dependencygroupIdcom.querydsl/groupIdartifactIdquerydsl-jpa/artifactIdversion4.4.0/version
/dependencydependencygroupIdcom.querydsl/groupIdartifactIdquerydsl-apt/artifactIdversion4.4.0/versionscopeprovided/scope
/dependency
然后我们需要添加一个 Q 实体类该类将用于构建 QueryDSL 查询语句。可使用官方提供的 Maven 插件生成 Q 类代码示例代码如下
buildpluginsplugingroupIdcom.mysema.maven/groupIdartifactIdapt-maven-plugin/artifactIdversion1.3.2/versionexecutionsexecutiongoalsgoalprocess/goal/goalsconfigurationoutputDirectorytarget/generated-sources/java/outputDirectoryprocessorcom.querydsl.apt.jpa.JPAAnnotationProcessor/processor/configuration/execution/executions/plugin/plugins
/build
Entity
Table(name user)
public class User {IdGeneratedValue(strategy GenerationType.IDENTITY)private Long id;Column(name username)private String username;Column(name age)private Integer age;Column(name email)private String email;// 省略 getter 和 setter 方法
}
Generated(com.querydsl.codegen.EntitySerializer)
public class QUser extends EntityPathBaseUser {private static final long serialVersionUID -777444987L;public static final QUser user new QUser(user);public final NumberPathInteger age createNumber(age, Integer.class);public final StringPath email createString(email);public final NumberPathLong id createNumber(id, Long.class);public final StringPath username createString(username);public QUser(String variable) {super(User.class, forVariable(variable));}public QUser(Path? extends User path) {super(path.getType(), path.getMetadata());}public QUser(PathMetadata metadata) {super(User.class, metadata);}}
现在我们就可以使用 QueryDSL 进行复杂查询了。以下是一个示例代码用于查询年龄大于等于20岁并且邮箱包含 example.com 的用户列表
Repository
public interface UserRepository extends JpaRepositoryUser, Long, QuerydslPredicateExecutorUser {}
Service
public class UserServiceImpl implements UserService {Autowiredprivate UserRepository userRepository;Overridepublic ListUser findUsersByCondition(String email, Integer age) {QUser qUser QUser.user;BooleanBuilder builder new BooleanBuilder();if (StringUtils.isNotBlank(email)) {builder.and(qUser.email.endsWithIgnoreCase(email));}if (age ! null) {builder.and(qUser.age.goe(age));}return (ListUser) userRepository.findAll(builder.getValue());}}
在 UserServiceImpl 的 findUsersByCondition 方法中我们首先创建了一个 QUser 对象然后使用 BooleanBuilder 对象来构建查询条件使用 endsWithIgnoreCase() 方法和 goe() 方法来构造查询条件。最后我们将构建出来的查询条件传递给 findAll 方法进行查询。
5.3 使用 Native SQL 查询
在某些情况下需要执行原生的 SQL 查询语句。Spring Data JPA 提供了 Query 注解来支持使用原生 SQL 查询数据。在 Query 注解中设置 nativeQuerytrue 即可执行原生 SQL 语句。
以下示例代码演示了如何使用原生 SQL 查询 age 大于等于 18 的用户。
public interface UserRepository extends JpaRepositoryUser, Long {Query(value SELECT * FROM user WHERE age ?1, nativeQuery true)ListUser findByAgeGreaterThanEqual(Integer age);
}// 使用
userRepository.findByAgeGreaterThanEqual(18);