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

Spring Boot中如何执行编程式动态拼接的SQL语句

Spring Boot 实现动态SQL执行的轻量方案

@Query 注解属于Spring Data JPA的静态声明式查询,SQL逻辑在编译期就固定,确实不支持运行时动态拼接。如果只需要简单JDBC能力实现动态查询,不需要额外引入复杂框架,Spring Boot官方自带的组件就能满足需求:

  • 首选方案:JdbcTemplate(最匹配简单JDBC查询需求)
    只要项目引入了spring-boot-starter-jdbc、spring-boot-starter-data-jpa任意一个JDBC相关起步依赖,Spring Boot会自动完成JdbcTemplate的装配,直接注入即可使用。它完全支持手动拼接SQL逻辑,同时提供预编译参数绑定能力避免SQL注入,支持结果自动映射为Map、自定义实体类。
    示例代码:

    @Service
    public class BizQueryService {
        private final JdbcTemplate jdbcTemplate;
    
        public BizQueryService(JdbcTemplate jdbcTemplate) {
            this.jdbcTemplate = jdbcTemplate;
        }
    
        // 动态查询用户列表示例
        public List<User> listUser(Long minId, String nameKeyword) {
            StringBuilder sql = new StringBuilder("SELECT id, username, create_time FROM sys_user WHERE 1 = 1");
            List<Object> queryParams = new ArrayList<>();
    
            // 按需拼接查询条件
            if (minId != null) {
                sql.append(" AND id >= ?");
                queryParams.add(minId);
            }
            if (nameKeyword != null && !nameKeyword.isBlank()) {
                sql.append(" AND username LIKE ?");
                queryParams.add("%" + nameKeyword + "%");
            }
    
            // 执行查询,直接映射为User实体
            return jdbcTemplate.query(
                    sql.toString(),
                    new BeanPropertyRowMapper<>(User.class),
                    queryParams.toArray()
            );
        }
    }
    

    如果不需要映射实体,直接调用queryForList方法就能返回List<Map<String, Object>>结构的结果,开发简易接口足够用。

  • 备选方案:JPA环境下直接用EntityManager
    如果项目已经深度使用Spring Data JPA,不想额外混用JdbcTemplate,可以直接注入EntityManager执行动态原生SQL:

    @Repository
    public class UserRepository {
        @PersistenceContext
        private EntityManager entityManager;
    
        public List<User> dynamicQuery(Long minId) {
            StringBuilder sql = new StringBuilder("SELECT * FROM sys_user WHERE 1 = 1");
            Map<String, Object> params = new HashMap<>();
            if (minId != null) {
                sql.append(" AND id >= :minId");
                params.put("minId", minId);
            }
            Query query = entityManager.createNativeQuery(sql.toString(), User.class);
            params.forEach(query::setParameter);
            return query.getResultList();
        }
    }
    

注意:动态拼接SQL时绝对不要直接把用户传入的参数拼接到SQL字符串中,必须用预编译占位符传参,避免SQL注入漏洞。

如果后续动态查询的条件、关联逻辑变得非常复杂,再考虑引入MyBatis的XML动态SQL、或者Spring Data JPA的Specification能力即可,对于当前简易RESTful API的开发需求,上面两个方案足够轻量,不需要额外引入第三方依赖。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 23:45:46