2023年如何在JdbcClient/JdbcTemplate中处理SQL WHERE子句动态条件?
处理JdbcClient动态WHERE条件的替代方案
方案1:用条件列表+String.join构建WHERE子句
这种方式比直接拼接字符串更整洁,还能避免WHERE 1=1的冗余写法:
@GetMapping("/user") public Iterable<User> listByConditions(@RequestParam(required = false) String name, @RequestParam(required = false) Integer sex) { MapSqlParameterSource params = new MapSqlParameterSource(); List<String> whereClauses = new ArrayList<>(); if (name != null) { whereClauses.add("`name` = :name"); params.addValue("name", name); } if (sex != null) { whereClauses.add("`sex` = :sex"); params.addValue("sex", sex); } StringBuilder sqlBuilder = new StringBuilder(""" SELECT `id`, `name`, `sex` FROM `user` """); if (!whereClauses.isEmpty()) { sqlBuilder.append("WHERE ").append(String.join(" AND ", whereClauses)); } sqlBuilder.append(""" ORDER BY `id` """); return jdbcClient.sql(sqlBuilder.toString()) .params(params) .query(User.class) .list(); }
把每个有效条件存进列表,最后统一拼接,逻辑清晰,也不会产生多余的SQL片段。
方案2:Spring 6.1+自带的动态SQL模板
如果你的项目用Spring 6.1及以上版本,JdbcClient支持直接在多行字符串里写动态SQL逻辑,语法和MyBatis类似但不用XML:
@GetMapping("/user") public Iterable<User> listByConditions(@RequestParam(required = false) String name, @RequestParam(required = false) Integer sex) { return jdbcClient.sql(""" SELECT `id`, `name`, `sex` FROM `user` <if name='name != null'> WHERE `name` = :name <if name='sex != null'> AND `sex` = :sex </if> <else if name='sex != null'> WHERE `sex` = :sex </if> ORDER BY `id` """) .param("name", name) .param("sex", sex) .query(User.class) .list(); }
直接把条件判断嵌在SQL字符串里,完美适配你喜欢多行字符串的需求,不用手动拼接SQL片段。
方案3:Querydsl实现类型安全的动态查询
如果想避免手写SQL时的字段名拼写错误,可以用Querydsl和JdbcClient结合,实现类型安全的动态查询:
@GetMapping("/user") public Iterable<User> listByConditions(@RequestParam(required = false) String name, @RequestParam(required = false) Integer sex) { QUser user = QUser.user; SQLQuery<User> query = new SQLQuery<>(new MySQLTemplates(), new JdbcConnectionProvider(dataSource)) .select(user) .from(user); if (name != null) { query.where(user.name.eq(name)); } if (sex != null) { query.where(user.sex.eq(sex)); } query.orderBy(user.id.asc()); // 提取生成的SQL和参数 String sql = query.getSQL().getSQL(); MapSqlParameterSource params = new MapSqlParameterSource(); query.getSQL().getBindings().forEach(binding -> params.addValue(binding.getVariable(), binding.getValue()) ); return jdbcClient.sql(sql) .params(params) .query(User.class) .list(); }
需要提前配置Querydsl生成实体对应的Q类,所有字段调用都是类型安全的,不会出现字段名写错的问题,适合复杂的动态查询场景。
内容的提问来源于stack exchange,提问作者tzq0301
相关产品推荐
相关产品推荐

