spring data jpa复杂多条件查询

本文介绍如何在Java项目中使用JPA进行排序及分页操作,包括按外键关联实体属性排序,并展示了如何实现复杂的多条件查询,如外键关联查询、或查询、外键in查询和id的in查询。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一.排序与分页

// 排序
Direction direction = Direction.DESC;
//directionStr为前端传值,asc代表正序
if ("asc".equals(directionStr)) {
	direction = Direction.ASC;
}
//默认使用datetime字段进行排序
String sortProperty = "datetime";
//sortParam为前端传的排序字段
if (UtilValidate.isNotEmpty(sortParam)) {
	sortProperty = sortParam;
}
Sort sort = new Sort(direction, sortProperty);

// 分页
// pageNumParam为页码,默认为0,pageSizeParam为每页条数
Pageable pageable = PageRequest.of(pageNumParam, pageSizeParam, sort);

注意:

如果想要按照外键关联实体的某个属性进行排序,sortProperty直接改为对应的 “实体名.属性名” 即可:

1.比如一个User实体对象,外键一对一关联地址实体对象Address,如果希望可以通过地址对象的id字段排序,那么sortProperty就应该传 “address.id” 。

@Entity
@Table(name="t_user")
public class User{
	@Id
	private Long id;

	@ManyToOne(fetch=FetchType.EAGER)
	@JoinColumn(name = "address_id")
	@NotFound(action=NotFoundAction.IGNORE)
	private Address address;
	
	/**
	 * 登录名
	 */
	@Column
	private String username;

	/**
	 * 状态
	 */
	@Column
	private Integer state;

	/**
	 * 所属机构
	 */
	@ManyToOne(fetch=FetchType.EAGER)
	@JoinColumn(name = "department_id")
	@NotFound(action=NotFoundAction.IGNORE)
	private Department department;

	/**
	 * 注册时间
	 */
	@Column
	private Long datetime;
}

2.项目使用的是oracle数据库,使用这种写法刚开始一直报错,排查后发现是配置的oracle方言的问题,如果有同样使用oracle数据库的小伙伴需要注意下,以下是修改的相关配置项:

#spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.OracleDialect
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.Oracle9Dialect

二.复杂查询

以下的复杂查询包含了4种类型:

1.外键关联查询 — 标注1

2.或查询 — 标注2

3.外键in查询 — 标注3

4.id的in查询 — 标注4

使用JPA进行复杂多条件查询,一般都需要重写JpaSpecificationExecutor接口中的方法:

public interface JpaSpecificationExecutor<T> {

    T findOne(Specification<T> spec);

    List<T> findAll(Specification<T> spec);

    Page<T> findAll(Specification<T> spec, Pageable pageable);

    List<T> findAll(Specification<T> spec, Sort sort);

    long count(Specification<T> spec);
}

我们此处需要使用的是Page findAll(Specification spec, Pageable pageable)方法,所以要针对它进行重写:

// 假设此处查询的是用户列表
return userRepository.findAll(new Specification() {
	@Override
	public Predicate toPredicate(Root root, CriteriaQuery query, CriteriaBuilder cb) {
		List<Predicate> pList = new ArrayList<Predicate>();
		Predicate[] ps = new Predicate[pList.size()];
		List<Predicate> stateList = new ArrayList<Predicate>();
		Predicate[] statePs = new Predicate[stateList.size()];
		
		// 查询用户表中未删除的地址 (标注1)
		// 假设address是用户表User中的外键关联,存放地址信息,state为0代表有效
		pList.add(cb.equal(root.join("address").get("state"), 0));
		
		//查询状态为10-未审核或0-已审核状态的用户 (标注2)
		stateList.add(cb.equal(root.get("state"), 0));
		stateList.add(cb.equal(root.get("state"),10));
		pList.add(cb.or(stateList.toArray(statePs)));
		
		// 时间查询
		pList.add(cb.between(root.get("datetime"), start, end));
				
		// 机构查询 (标注3)
		if (UtilValidate.isNotEmpty(departsStr)) {
			Predicate pDepart = inQuery(departsStr, "department", cb, root);
			pList.add(pDepart);
		}
			
		query.where(pList.toArray(ps));
		return null;
	}
}, pageable);

以下为使用到的外键关联in查询的方法:

public Predicate inQuery(String entityIds, String entityName, CriteriaBuilder cb, Root root) {
	List<Predicate> list = new ArrayList<>();
	String[] ids = entityIds.split(",");
	if (ids != null && ids.length > 0) {
		In<Object> in = cb.in(root.join(entityName).get("id"));
		for (String id : ids) {
			Long idNum = Long.parseLong(id);
			in.value(idNum);
		}
		list.add(in);
	}

	Predicate[] p = new Predicate[list.size()];
	return cb.and(list.toArray(p));
}

如果希望进行id的in查询,只需把root.join(entityName).get(“id”)改为root.get(“id”)即可(标注4)。

### 回答1: Spring Data JPA 支持多条件查询,可以使用 @Query 注解或者方法名规则来实现。 1. 使用 @Query 注解 可以在 Repository 接口中使用 @Query 注解来定义查询语句,例如: ```java @Repository public interface UserRepository extends JpaRepository<User, Long> { @Query("select u from User u where u.name = ?1 and u.age > ?2") List<User> findByNameAndAgeGreaterThan(String name, int age); } ``` 这个例子中,我们定义了一个方法 findByNameAndAgeGreaterThan,它接受两个参数 name 和 age,使用 @Query 注解来定义查询语句,查询条件为 name 和 age。这个方法会返回一个 List<User> 对象,包含满足条件的所有用户。 2. 使用方法名规则 Spring Data JPA 还支持使用方法名规则来定义查询方法,例如: ```java @Repository public interface UserRepository extends JpaRepository<User, Long> { List<User> findByNameAndAgeGreaterThan(String name, int age); } ``` 这个例子中,我们定义了一个方法 findByNameAndAgeGreaterThan,它接受两个参数 name 和 age,方法名符合方法名规则,Spring Data JPA 会自动解析方法名,生成查询语句,查询条件为 name 和 age。这个方法会返回一个 List<User> 对象,包含满足条件的所有用户。 总结 Spring Data JPA 支持多条件查询,可以使用 @Query 注解或者方法名规则来实现。使用 @Query 注解可以自定义查询语句,使用方法名规则可以简化代码,提高开发效率。 ### 回答2: Spring Data JPASpring Framework 的子项目之一,可简化与数据库的 CRUD 操作。在 JPA 规范的基础上,Spring Data JPA 进一步简化了 CRUD 操作的过程,特别是在使用多条件查询时具有较大的便利性。Spring Data JPA 中的多条件查询主要可以使用以下两种方式: 一、通过命名查询实现多条件查询Spring Data JPA 提供了基于命名查询的方式来查询数据,方便快捷,使得查询和业务代码分离,具有很好地维护性和灵活性。我们只需要定义一个符合语法规范的 JQL 语句,然后通过 @Query 注解将其绑定到自定义的查询方法上。参数列表中可以配置多个条件Spring Data JPA 会自动将这些条件组装成一个完整的 SQL 查询语句,然后执行查询操作。 举例来说,如果我们要查询年龄在 20 到 30 岁之间,并且居住城市为北京的用户信息,可以通过如下的方式定义一个命名查询: @Query("select u from User u where u.age >= ?1 and u.age <= ?2 and u.city = ?3") List<User> findByAgeAndCityBetween(int minAge, int maxAge, String city); 在这个例子中,我们定义了一个名为“findByAgeAndCityBetween”的查询方法,使用了 JPA 的命名查询语法,从 User 实体中查询符合条件的记录,并返回查询结果的列表。 二、通过 Specification 来实现多条件查询Spring Data JPA 还提供了通过 Specification 来实现多条件查询的方式。Specification 是 Spring Data JPA 中的一个接口,我们可以通过实现 Specification 接口的方式来构造查询条件。它提供了一个 where 子句,包含了查询条件,是一个单独的类。我们只需要实现 Specification 接口中的 toPredicate 方法,将查询条件组装成一个 Predicate 对象,然后传递给 JPA 的 CriteriaQuery 对象,就可以实现多条件查询的效果。 例如,我们要查询所有年龄在 20 到 30 岁之间,并且居住城市为北京的用户信息,可以通过如下的方式来实现: public static Specification<User> searchUsers(int minAge, int maxAge, String city) { return new Specification<User>() { @Override public Predicate toPredicate(Root<User> root, CriteriaQuery<?> query, CriteriaBuilder builder) { List<Predicate> predicates = new ArrayList<>(); predicates.add(builder.between(root.get("age"), minAge, maxAge)); predicates.add(builder.equal(root.get("city"), city)); return builder.and(predicates.toArray(new Predicate[predicates.size()])); } }; } 在这个例子中,我们定义了一个名为“searchUsers”的 Specification 接口实现类,使用了 JPA 的 CriteriaBuilder 和 CriteriaQuery API 实现了多条件查询。我们通过 root.get("") 方法来获取查询的属性,builder.between() 方法来获取查询区间,builder.equal() 方法来获取等值查询。最后将多个查询条件封装成了一个 Predicate 对象,通过 builder.and() 方法进行逻辑与操作。我们可以将这个 Specification 对象传递给 JpaRepository 的 findAll() 方法,Spring Data JPA根据 Specification 来动态生成 SQL 查询语句,然后执行查询操作。 综上所述,Spring Data JPA 中的多条件查询可以通过以上两种方式来实现,不论是基于命名查询还是 Specification,都具有较高的实用性和便利性。在实际开发中,可以根据具体情况来选择不同的查询方式,提高代码的可读性和可维护性。 ### 回答3: Spring Data JPASpring对于JPA的实现方式,它可以简化复杂JPA操作,并提供了很多便捷的查询方法。在开发过程中,我们经常需要使用多个条件进行查询,在Spring Data JPA中也提供了多种实现方式。 1.使用@Query注解 在实体类对应的Repository中,我们可以使用@Query注解来自定义查询语句。 比如我们需要查询age大于20,name为xiao的User,则可以定义如下方法: @Query("select u from User u where u.age > 20 and u.name = 'xiao'") List<User> findByAgeAndName(); 2.使用Specification接口 另一种实现方式是使用Specification接口。它可以动态的构造查询条件,设计精细,可扩展性强。 首先定义一个Specification接口,比如我们需要查询age大于20,name为xiao的User: public static Specification<User> findByAgeAndName() { return (root, query, cb) -> { List<Predicate> predicates = new ArrayList<>(); predicates.add(cb.gt(root.get("age"), 20)); predicates.add(cb.equal(root.get("name"), "xiao")); query.where(predicates.toArray(new Predicate[predicates.size()])); return query.getRestriction(); }; } 然后在Repository中使用这个Specification: List<User> userList = userRepository.findAll(findByAgeAndName()); 这样就能够查询到age大于20,name为xiao的User。 3.使用QueryDSL QueryDSL可以提供类型安全和可读性较高的查询语法。它可以通过代码生成器自动生成查询类,可以减少手写SQL的时间和错误。 首先按照官方文档进行依赖配置和代码生成器的使用,生成查询类后进行查询操作: QUser user = QUser.user; List<User> userList = userRepository.findAll(user.age.gt(20).and(user.name.eq("xiao"))); 以上便是Spring Data JPA多条件查询方法,可以根据具体情况选择最适合自己的方式。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

春日安然

可以赏个鸡腿吃嘛~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值