You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Boot 3.3.3升级后findByEmail方法返回Optional.empty问题排查

问题原因及解决方案

问题背景

Spring Boot 2.5.x升级至3.3.3后,UserRepository的findByEmail(String email)方法始终返回Optional.empty,但findAll()能正常返回包含目标邮箱的用户记录;实体类User的email字段使用了@Convert(converter = QueryableStringEncryptor.class)做字段加密。

核心原因

Spring Data JPA 3.x版本对属性转换器(Attribute Converter)的查询参数处理逻辑发生了变更:

  • 在2.x版本中,Spring Data会自动将Repository查询方法的参数,通过实体字段上的@Convert转换器进行转换(即把明文邮箱加密后再去数据库匹配)。
  • 3.x版本中,当Repository同时继承QuerydslPredicateExecutor时,Spring Data的参数转换逻辑优先级或触发条件改变,导致findByEmail方法的明文参数未经过加密转换器处理,直接以明文去匹配数据库中存储的加密值,自然无法找到对应记录。

解决方法

方法1:显式使用@Query手动处理参数加密

在findByEmail方法上添加@Query注解,通过SpEL表达式调用Spring容器中的加密转换器,确保查询时用加密后的值匹配数据库:

@RepositoryRestResource(exported = false)
public interface UserRepository extends JpaRepository<User, Long>, QuerydslPredicateExecutor<User> {
    Stream<UserDashboardSearchProjection> findByEmailIsNotNull();
    Optional<User> findById(Long userId);

    @Query("SELECT u FROM User u WHERE u.email = #{@queryableStringEncryptor.encrypt(:email)}")
    Optional<User> findByEmail(@Param("email") String email);
}

前提:QueryableStringEncryptor需被注册为Spring Bean。

方法2:移除QuerydslPredicateExecutor(若业务不需要)

如果项目未用到QuerydslPredicateExecutor的功能,直接从Repository继承列表中移除该接口,Spring Data JPA会恢复默认的参数转换逻辑,findByEmail方法会自动将参数通过转换器加密后查询。

方法3:自定义Querydsl Predicate处理参数加密

若必须保留QuerydslPredicateExecutor,需在构建查询Predicate时手动对邮箱参数加密:

// 业务代码中调用Querydsl查询的示例
@Autowired
private UserRepository userRepository;
@Autowired
private QueryableStringEncryptor encryptor;

public Optional<User> findUserByEmail(String email) {
    String encryptedEmail = encryptor.encrypt(email);
    QUser qUser = QUser.user;
    return userRepository.findOne(qUser.email.eq(encryptedEmail));
}

方法4:检查转换器的@Converter注解配置

确保QueryableStringEncryptor类上的@Converter注解设置了autoApply = true,让Spring自动将转换器应用到所有匹配类型的字段查询中:

@Converter(autoApply = true)
public class QueryableStringEncryptor implements AttributeConverter<String, String> {
    @Override
    public String convertToDatabaseColumn(String attribute) {
        // 加密逻辑实现
    }

    @Override
    public String convertToEntityAttribute(String dbData) {
        // 解密逻辑实现
    }
}

内容的提问来源于stack exchange,提问作者Ballazx

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 18:31:07