如何用JDBC动态生成带多条件组合的WHERE子句查询?
动态生成JDBC多条件WHERE子句(处理多参数对)
作为JDBC新手,处理动态多条件查询确实容易懵,但核心思路其实很清晰——用参数化SQL避免注入,动态拼接条件块,下面一步步给你讲清楚:
核心原则:永远用参数化查询,别直接拼字符串
直接把参数值拼到SQL里会导致SQL注入漏洞,而且处理字符串转义(比如state里的单引号)也很麻烦,所以一定要用PreparedStatement的?占位符。
步骤1:构建动态SQL语句
先保留你的基础SELECT和JOIN部分,然后根据参数对的数量,动态生成(spsuppno = ? AND spstate = ?)的OR块:
代码示例(原生JDBC)
// 先定义一个简单的类来装参数对(也可以用数组或者Map,类更清晰) class SupplierParamPair { int supplierNumber; String stateCode; public SupplierParamPair(int supplierNumber, String stateCode) { this.supplierNumber = supplierNumber; this.stateCode = stateCode; } } public List<Map<String, Object>> querySuppliers(List<SupplierParamPair> paramPairs) throws SQLException { // 基础SQL模板 StringBuilder sqlBuilder = new StringBuilder(); sqlBuilder.append("SELECT sp.*, se.sepurch_email, issuppno, isstates ") .append("FROM supplier sp ") .append("LEFT JOIN suppliser_email se ON spsuppno = sesuppno AND spstate = sestate ") .append("LEFT JOIN int_supplier ON spsuppno = issuppno AND islive = 'Y' ") .append("WHERE "); List<Object> paramValues = new ArrayList<>(); if (!paramPairs.isEmpty()) { // 循环生成每个条件块 for (int i = 0; i < paramPairs.size(); i++) { if (i != 0) { sqlBuilder.append(" OR "); } // 添加带占位符的条件 sqlBuilder.append("(spsuppno = ? AND spstate = ?)"); // 把参数值加入列表,顺序要和占位符对应 SupplierParamPair pair = paramPairs.get(i); paramValues.add(pair.supplierNumber); paramValues.add(pair.stateCode); } } else { // 处理空参数的情况:避免WHERE后面为空导致SQL语法错误 // 这里用1=0返回空结果,你也可以根据业务改成返回所有数据(比如1=1) sqlBuilder.append("1 = 0"); } // 执行查询 try (Connection conn = yourConnectionMethod(); // 替换成你获取数据库连接的方法 PreparedStatement pstmt = conn.prepareStatement(sqlBuilder.toString())) { // 逐个设置参数 for (int i = 0; i < paramValues.size(); i++) { pstmt.setObject(i + 1, paramValues.get(i)); } // 处理结果集 List<Map<String, Object>> result = new ArrayList<>(); try (ResultSet rs = pstmt.executeQuery()) { ResultSetMetaData metaData = rs.getMetaData(); int columnCount = metaData.getColumnCount(); while (rs.next()) { Map<String, Object> row = new HashMap<>(); for (int i = 1; i <= columnCount; i++) { row.put(metaData.getColumnName(i), rs.getObject(i)); } result.add(row); } } return result; } }
步骤2:关键注意点
- 参数顺序不能错:每个
(spsuppno = ? AND spstate = ?)对应两个参数,所以参数列表要按「第一个pair的number → 第一个pair的state → 第二个pair的number → 第二个pair的state」的顺序添加。 - 空参数处理:如果没有传入任何参数对,一定要给WHERE加一个合法条件,不然SQL会变成
WHERE,直接报错。 - 避免SQL注入:绝对不要做
sqlBuilder.append("spsuppno = " + pair.supplierNumber)这种拼接,哪怕是数字类型也不行——参数化是最安全的方式。
扩展:用Spring JdbcTemplate简化代码
如果之后你用Spring框架,JdbcTemplate会帮你简化很多重复代码:
@Autowired private JdbcTemplate jdbcTemplate; public List<Supplier> querySuppliersWithSpring(List<SupplierParamPair> paramPairs) { String baseSql = "SELECT sp.*, se.sepurch_email, issuppno, isstates " + "FROM supplier sp " + "LEFT JOIN suppliser_email se ON spsuppno = sesuppno AND spstate = sestate " + "LEFT JOIN int_supplier ON spsuppno = issuppno AND islive = 'Y' " + "WHERE "; StringBuilder whereClause = new StringBuilder(); List<Object> params = new ArrayList<>(); for (int i = 0; i < paramPairs.size(); i++) { if (i > 0) whereClause.append(" OR "); whereClause.append("(spsuppno = ? AND spstate = ?)"); SupplierParamPair pair = paramPairs.get(i); params.add(pair.supplierNumber); params.add(pair.stateCode); } if (whereClause.length() == 0) { whereClause.append("1 = 0"); } String finalSql = baseSql + whereClause.toString(); // 映射结果到实体类 return jdbcTemplate.query(finalSql, params.toArray(), (rs, rowNum) -> { Supplier supplier = new Supplier(); supplier.setSuppNo(rs.getInt("spsuppno")); supplier.setState(rs.getString("spstate")); supplier.setPurchaseEmail(rs.getString("sepurch_email")); // 其他字段映射... return supplier; }); }
这样不管参数对有多少个,都能自动生成对应的WHERE条件,而且完全安全。
内容的提问来源于stack exchange,提问作者J.L
相关产品推荐
相关产品推荐

