jpa 动态查询

本文介绍了如何使用 Spring Data JPA 的 Specifications 功能进行动态查询,详细讲解了 Specifications 的优势和使用方法,以及如何结合 Web 请求处理动态查询。同时对比了 Query by Example 的查询方式,最后分享了自己实现 Web 请求动态查询的步骤和思路。
摘要由CSDN通过智能技术生成

上一篇我们说到了spring-data-rest 和spring-data-jpa 使用的主要意义。主要目的就是为了减少模板化的代码,那么针对某个特定的repository的查询,我们是不是也可以将查询简化呢?答案当然是肯定的。

我们先来看一下jpa有哪些查询方法:

1.Query methods

The JPA module supports defining a query manually as String or have it being derived from the
method name.

JPA 模块支持手动定义一个查询字符串或者从一个方法名中导出查询。

用法如下:

public interface UserRepository extends Repository<User, Long> {
 List<User> findByEmailAddressAndLastname(String emailAddress, String lastname);
}
对应的生成的查询为:select u from User u where u.emailAddress = ?1 and u.lastname = ?2.

当然你也可以直接指定查询语句:

public interface UserRepository extends JpaRepository<User, Long> {
 @Query("select u from User u where u.emailAddress = ?1")
 User findByEmailAddress(String emailAddress);
}
若是想使用原生的sql,只需要开启 nativeQuery =true

public interface UserRepository extends JpaRepository<User, Long> {
 @Query(value = "SELECT * FROM USERS WHERE EMAIL_ADDRESS = ?1", nativeQuery =
true)
 User findByEmailAddress(String emailAddress);
}

如果我们只是在后台内部做查询,不涉及到前端web请求查询,那么命名查询是一个不错的选择。因为如果走web请求,想要实现动态查询,那么你就不得不去写很多个方法或者写很多条查询语句了。

2.Stored procedures

The JPA 2.1 specification introduced support for calling stored procedures via the JPA criteria query
API. We Introduced the @Procedure annotation for declaring stored procedure metadata on a
repository method.

JPA2.1 规范通过JPA条件查询API引进了对存储过程的支持。在一个库方法上,通过使用@Procedure声明存储过程元数据。

@Entity
@NamedStoredProcedureQuery(name = "User.plus1", procedureName = "plus1inout",
parameters = {
 @StoredProcedureParameter(mode = ParameterMode.IN, name = "arg", type = Integer
.class),
 @StoredProcedureParameter(mode = ParameterMode.OUT, name = "res", type =
Integer.class) })
public class User {}
在方法上调用存储过程:

@Procedure("plus1inout")
Integer explicitlyNamedPlus1inout(Integer arg);

因为我们涉及到的都是单表查询,而且没有复杂的逻辑要处理,所以存储过程还是用在它该用的地方吧!


3.Specifications

Specifications can easily be used to build an extensible set of
predicates on top of an entity that then can be combined and used with JpaRepository without the
need to declare a query (method) for every needed combination。

Specifications 可以容易地在一个predicate实体之上构造可扩展的predicates集合,它可以被用来组合,而不需要为每次的组合声明一个查询(方法)。

看到这里,看到了希望,因为它很明确的说明出了查询条件是可以组合的。


要想使用Specifications,我们自己的repository一定要继承JpaSpecificationExecutor接口

public interface CustomerRepository extends CrudRepository<Customer, Long>,
JpaSpecificationExecutor {
 List<T> findAll(Specification<T> spec);
}


下面是如何构造自己的specification


public class CustomerSpecs {
 public static Specification<Customer> isLongTermCustomer() {
 return new Specification<Customer>() {
 public Predicate toPredicate(Root<Customer> root, CriteriaQuery<?> query,
 CriteriaBuilder builder) {
 LocalDate date = new LocalDate().minusYears(2);
 return builder.lessThan(root.get(_Customer.createdAt), date);
 }
 };
 }
 public static Specification<Customer> hasSalesOfMoreThan(MontaryAmount value) {
 return new Specification<Customer>() {
 public Predicate toPredicate(Root<T> root, CriteriaQuery<?> query,
 CriteriaBuilder builder) {
 // build query here
 }
 };
 }
}



构造好specifications 后就剩下使用了:

MonetaryAmount amount = new MonetaryAmount(200.0, Currencies.DOLLAR);
List<Customer> customers = customerRepository.findAll(
 where(isLongTermCustomer()).or(hasSalesOfMoreThan(amount)));
它的用法很简单,关键是它为我们提供了一种动态查询的可能。


4.Query by Example

Query by Example (QBE) is a user-friendly querying technique with a simple interface. It allows
dynamic query creation and does not require to write queries containing field names. In fact,
Query by Example does not require to write queries using store-specific query languages at all.

通过  Example查询是一种通过实现简单接口的很友好的查询技术。它允许创建动态查询,并且不需要写包含 域的名字的查询。实际上,QBE不需要写任何特定存储查询语言。


看到这里心里不免又窃喜了一下,看来要实现动态查询还有第二种选择。

先来看看用法:

• Probe: That is the actual example of a domain object with populated fi
Spring Data JPA 提供了强大的动态查询能力,允许开发者在运行时构建查询,而不需要硬编码SQL语句。这种动态查询的实现通常是通过使用Spring Data JPARepository接口中的特定方法来完成的。 在Spring Data JPA中,可以通过以下几种方式实现动态查询: 1. 使用JPA Specification:通过定义一个Specification对象来描述查询条件,然后通过Repository接口的`findAll()`方法传递这个Specification对象。Specification允许开发者使用一系列的谓词组合成复杂的查询逻辑。 2. 使用Spring Data JPAQueryDSL集成:QueryDSL提供了一种类型安全的方式来构建查询,它允许开发者使用流畅的API来构建查询,而不是编写字符串形式的查询语句。 3. 使用Criteria API:通过Criteria API可以构建类型安全的查询,并且可以动态地构建查询条件。Criteria API是Java持久化API的一部分,提供了一种程序化的查询语言,可以避免SQL注入等安全问题。 4. 使用JPQL(Java Persistence Query Language)或原生SQL查询:在某些复杂的查询场景下,可以使用JPQL来构建查询语句,或者直接使用原生SQL语句。 示例代码(使用Specification动态查询): ```java public interface UserRepository extends JpaRepository<User, Long>, JpaSpecificationExecutor<User> { } public class UserSpecification { public static Specification<User> hasNameLike(final String name) { return (Specification<User>) (root, query, cb) -> cb.like(root.get("name"), "%" + name + "%"); } } // 在业务逻辑中使用 List<User> users = userRepository.findAll(UserSpecification.hasNameLike("张三")); ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值