spring data JPA 模糊查询 --- 使用 LIKE --- 的写法

方法一
1.  Controller层:
方法参数一定要加 "%"+name+"%"

@RestController
public class UserController {

    @Autowired
    private TeamRepository teamRepository;

    @GetMapping("/findByNameLike")
    public List<Team> findByNameLike(String name) {
        // 一定要加 "%"+参数名+"%"
        return teamRepository.findByNameLike("%"+name+"%");
    }
}

2. Dao层:
 一定要使用 JPA 规定的形式 findBy + 参数名 + Like(参数)

public interface TeamRepository extends JpaRepository<Team, String> {
    List<Team> findByNameLike(String name);

 

方法二
1. Controller:

参数简单化

@RestController
public class UserController {

    @Autowired
    private TeamRepository teamRepository;

    @GetMapping("/findByNameLike")
    public List<Team> findByNameLike(String name) {
        return teamRepository.findByNameLike(name);
    }
}

2.Dao层:
自己定义 SQL 语句

/** 参数1 就是 ?1 ,参数2 就是 ?2   */
public interface TeamRepository extends JpaRepository<Team, String> {
    @Query(value = "select t from Team t where t.name like '%?1%'")
    List<Team> findByNameLike(String name);

 


原文地址: https://www.cnblogs.com/yang1314/p/9295764.html

<think>嗯,用户这次想深入了解SpringDataJPA的Specification动态查询机制。从用户引用的代码片段来看,ta应该已经接触过基础用法,现在需要系统性的原理剖析和进阶指导。注意到用户特别标注"引用仅供参考,不是真正需求",说明ta真正想要的是脱离具体案例的通用性知识体系。这很符合技术学习路径——当开发者看到他人代码后,往往会渴望掌握背后的设计哲学和完整能力图谱。用户可能遇到的实际痛点是:如何优雅处理多条件动态拼接?为什么需要Root/Query/CriteriaBuilder三件套?这正是Specification的核心价值所在。ta引用的代码里那个buildSpecification方法其实就展示了解决动态拼接的经典模式——用Predicate列表收集条件,最后用cb.and合成。考虑到用户刚接触可能存在的理解障碍,我需要强调几个关键概念:1)Specification本质是函数式接口,要解释清楚(root,query,cb)->{...}这种lambda写法2)必须展开说明CriteriaAPI三剑客的分工,特别是root.get("字段")这种类型安全操作的代价3)分页组合使用的实际场景很重要,用户可能没意识到Sort和Pageable能直接和Specification配合需要特别提醒性能陷阱。比如当用户看到代码里的"cb.like(...,"%"+str+"%")"时,可能不知道这种全模糊查询在数据量大时的危害,应该主动预警。还有N+1问题——动态查询最容易忽略的就是这个,得给出JPA2.1的EntityGraph解决方案。用户没有问但肯定需要的,是如何处理复杂嵌套条件。比如OR和AND组合时,现有文档很少说明cb.or(array)这种技巧,更不会提到criteriaBuilder.and(p1,cb.or(p2,p3))的嵌套写法。这个在电商多条件筛选中是刚需。最后要预判用户的后续动作。既然掌握了动态查询,下一步必然是优化,所以提前准备SpecificationExecutor扩展方案(CustomRepository),以及QueryDSL对比建议——特别是当ta需要动态选择表字段时,Specification其实很笨重。啊,差点忘了警告常见错误!很多开发者会忘记query.distinct(true),当关联查询出现重复数据时就懵了。还有动态类型转换的陷阱,比如root.get("id").as(String.class)在字段类型不匹配时不会立即报错...</think> 下面详细介绍Spring Data JPA中Specification动态查询的使用方法,结合核心概念和实际场景说明: ### 一、Specification 基础原理 1. **核心接口定义** `Specification<T>`是函数式接口,核心方法为: ```java Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder cb); ``` - `Root<T>`:查询的根对象(对应实体) - `CriteriaQuery`:构建查询的容器 - `CriteriaBuilder`:构造查询条件(=、>、like等) 2. **动态查询本质** 通过链式组合多个`Predicate`,实现SQL条件动态拼接,替代硬编码的JPQL语句。 --- ### 二、核心使用步骤 #### 1. 定义Specification ```java private Specification<User> buildSpec(String username, Boolean active) { return (root, query, cb) -> { List<Predicate> predicates = new ArrayList<>(); // 动态条件1:用户名模糊匹配 if (StringUtils.hasText(username)) { predicates.add(cb.like(root.get("username"), "%" + username + "%")); } // 动态条件2:激活状态精确匹配 if (active != null) { predicates.add(cb.equal(root.get("active"), active)); } return cb.and(predicates.toArray(new Predicate[0])); }; } ``` #### 2. 组合查询条件 ```java // 组合多条件 Specification<User> spec = Specification.where(buildNameSpec("张")) .and(buildStatusSpec(true)) .or(buildEmailSpec("@company.com")); ``` #### 3. 执行查询 ```java // 分页+排序 Pageable pageable = PageRequest.of(0, 10, Sort.by("createTime").descending()); // 关键调用 Page<User> result = userRepository.findAll(spec, pageable); ``` --- ### 三、进阶用法 #### 1. 关联查询处理 ```java Specification<Order> orderSpec = (root, query, cb) -> { Join<Order, User> userJoin = root.join("user"); // 关联用户表 return cb.like(userJoin.get("address"), "%北京%"); }; ``` #### 2. 复杂条件组合 ```java Specification<User> complexSpec = (root, query, cb) -> { Predicate namePred = cb.like(root.get("name"), "%李%"); Predicate agePred = cb.between(root.get("age"), 18, 30); // 嵌套条件: (name LIKE '%李%') OR (age BETWEEN 18 AND 30) return cb.or(namePred, agePred); }; ``` #### 3. 动态排序 ```java Specification<User> spec = ...; List<Order> orders = new ArrayList<>(); orders.add(cb.desc(root.get("createTime"))); query.orderBy(orders); // 动态注入排序 ``` --- ### 四、性能优化技巧 1. **避免N+1问题** ```java Specification<Post> spec = (root, query, cb) -> { root.fetch("comments"); // 立即加载关联对象 return cb.isNotNull(root.get("title")); }; ``` 2. **使用Tuple减少字段** ```java Specification<User> spec = ...; CriteriaQuery<Tuple> tupleQuery = cb.createTupleQuery(); tupleQuery.multiselect(root.get("id"), root.get("name")); ``` 3. **Predicate复用** ```java static Specification<User> activeUsers() { return (root, query, cb) -> cb.isTrue(root.get("active")); } ``` --- ### 五、典型应用场景 | 场景 | 实现方案 | |---------------------|----------------------------| | 后台管理系统筛选查询 | 多字段动态组合Specification | | 报表复杂条件导出 | 动态构造统计查询条件 | | 权限数据过滤 | 注入权限谓词到Specification | > ⚠️ **注意项**: > 1. 动态拼接时使用`root.get(fieldName)`而非字符串,需确保实体字段名准确 > 2. 关联查询注意`Fetch`与`Join`的区别(`Fetch`用于加载,`Join`用于条件) > 3. 分页时避免全表`COUNT(*)`,可通过`@QueryHints`添加数据库优化提示[^1] --- **引用标识说明** [^1]: 本文引用的Specification实现模式源于Spring Data JPA官方文档及实践案例,其动态查询设计符合JPA 2.1标准规范。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值