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

能否在Spring中创建支持动态WHERE列的@Query查询?

能否通过动态传入列名实现通用查询?

结论:你写的这种方式行不通

你当前的写法中,:column会被Spring Data JPA当作字符串参数处理,而不是作为数据库列名解析。比如调用getValue("name","Mike")时,实际执行的SQL会变成:

SELECT Name FROM Users WHERE 'name' = 'Mike'

这是在比较两个字符串字面量是否相等,而不是查询name列等于Mike的用户,完全达不到预期效果。

正确的实现方式

方式1:Spring Data JPA派生查询(简单场景首选)

如果只是针对固定的几个列做查询,直接定义派生方法即可,Spring会自动生成对应的SQL,无需手动写@Query:

public interface UserRepository extends JpaRepository<User, Long> {
    List<User> findByName(String name);
    List<User> findByEmail(String email);
    List<User> findByPhone(String phone);
}

优点是简单安全,无SQL注入风险;缺点是列多的话会生成大量重复方法。

方式2:SpEL动态构建原生查询(适合需要原生SQL的场景)

通过SpEL表达式#{#column}直接替换列名,但必须严格校验传入的列名,防止SQL注入:

public interface UserRepository extends JpaRepository<User, Long> {
    @Query(value = """
            SELECT * FROM Users WHERE #{#column} = :value
           """, nativeQuery = true)
    List<User> getValue(@Param("column") String column, @Param("value") String value);
}

调用时必须限制列名在合法范围内:

// 预先定义允许查询的列名集合
private static final Set<String> ALLOWED_COLUMNS = Set.of("name", "email", "phone");

public List<User> queryByColumn(String column, String value) {
    if (!ALLOWED_COLUMNS.contains(column)) {
        throw new IllegalArgumentException("非法列名:" + column);
    }
    return userRepository.getValue(column, value);
}

方式3:Criteria API动态查询(最安全的复杂场景方案)

用JPA的CriteriaAPI动态构建查询,完全避免SQL注入,还能灵活扩展查询条件:

@Service
public class UserService {
    @Autowired
    private EntityManager entityManager;

    public List<User> getByColumn(String column, String value) {
        CriteriaBuilder cb = entityManager.getCriteriaBuilder();
        CriteriaQuery<User> query = cb.createQuery(User.class);
        Root<User> root = query.from(User.class);

        // 校验列名是否存在于实体类中
        try {
            root.get(column);
        } catch (IllegalArgumentException e) {
            throw new IllegalArgumentException("非法列名:" + column);
        }

        query.select(root).where(cb.equal(root.get(column), value));
        return entityManager.createQuery(query).getResultList();
    }
}

优点是安全、灵活,适合需要动态组合多个条件的场景;缺点是代码量略多。

关键注意事项

无论用哪种动态列名的方式,必须校验传入的列名合法性,只允许查询预先定义的列,否则会存在严重的SQL注入风险。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 01:35:06