如何改造DbUtils的executeQuery方法支持带?参数的动态查询
DbUtils类executeQuery方法改造方案(支持带占位符的动态SQL)
核心改造思路
基于原有的无参数查询方法,新增重载方法支持带?占位符的动态SQL,通过Map<Integer, Object>传递参数位置与对应值(key为占位符的位置索引,从1开始;value为参数值,支持String、Integer等任意JDBC兼容类型),利用JDBC的PreparedStatement.setObject()自动适配参数类型,简化多类型参数的处理逻辑。
改造后完整代码示例
假设原DbUtils类已有getConnection()方法用于获取数据库连接,以下是改造后的实现:
import java.sql.*; import java.util.*; public class DbUtils { // 原有无参数查询方法(保留) public List<Map<String, Object>> executeQuery(String sql) throws SQLException { return executeQuery(sql, null); } // 新增支持带参数的查询方法 public List<Map<String, Object>> executeQuery(String sql, Map<Integer, Object> params) throws SQLException { // 使用try-with-resources自动关闭资源,避免手动关闭遗漏 try (Connection conn = getConnection(); PreparedStatement pstmt = conn.prepareStatement(sql)) { // 设置占位符参数 if (params != null && !params.isEmpty()) { for (Map.Entry<Integer, Object> entry : params.entrySet()) { int paramIndex = entry.getKey(); Object paramValue = entry.getValue(); // setObject自动适配参数类型,JDBC驱动会处理String、Integer、Long等常见类型 pstmt.setObject(paramIndex, paramValue); } } // 执行查询并处理结果集 try (ResultSet rs = pstmt.executeQuery()) { return convertResultSetToList(rs); } } } // 通用结果集转换方法:把ResultSet转为List<Map> private List<Map<String, Object>> convertResultSetToList(ResultSet rs) throws SQLException { List<Map<String, Object>> resultList = new ArrayList<>(); ResultSetMetaData metaData = rs.getMetaData(); int columnCount = metaData.getColumnCount(); while (rs.next()) { Map<String, Object> rowMap = new HashMap<>(); for (int i = 1; i <= columnCount; i++) { String columnName = metaData.getColumnName(i); rowMap.put(columnName, rs.getObject(i)); } resultList.add(rowMap); } return resultList; } // 假设已有获取数据库连接的方法(根据实际场景实现) private Connection getConnection() throws SQLException { // 示例:加载驱动并获取连接,实际需替换为你的数据库配置 Class.forName("com.mysql.cj.jdbc.Driver"); return DriverManager.getConnection("jdbc:mysql://localhost:3306/test", "root", "password"); } }
使用示例
单个参数场景
查询ID大于100的商品:
String sql = "select id,description,quantity from products where id>?"; Map<Integer, Object> params = new HashMap<>(); params.put(1, 100); // 第一个占位符(索引1)的值为Integer类型的100 DbUtils dbUtils = new DbUtils(); List<Map<String, Object>> products = dbUtils.executeQuery(sql, params);
多个参数场景
查询ID大于100且库存小于50的商品:
String sql = "select * from products where id>? and quantity<?"; Map<Integer, Object> params = new HashMap<>(); params.put(1, 100); params.put(2, 50); List<Map<String, Object>> products = dbUtils.executeQuery(sql, params);
关键细节说明
- 参数索引规则:JDBC中
PreparedStatement的占位符索引从1开始,而非0,所以Map的key必须对应正确的位置。 - 自动类型适配:
setObject()方法会根据参数的实际类型,自动映射为对应的SQL类型(如Integer对应INT,String对应VARCHAR等),无需手动判断类型调用setString()、setInt()等方法,简化代码。 - 资源安全:使用try-with-resources语法,自动关闭
Connection、PreparedStatement、ResultSet,避免数据库资源泄漏。 - 兼容原有逻辑:保留原无参数方法,通过重载实现扩展,不影响原有代码的使用。
可选优化:支持可变参数传参
如果觉得Map传递参数不够直观,可再新增一个支持可变参数的重载方法,按占位符顺序传递参数:
public List<Map<String, Object>> executeQuery(String sql, Object... params) throws SQLException { try (Connection conn = getConnection(); PreparedStatement pstmt = conn.prepareStatement(sql)) { if (params != null && params.length > 0) { for (int i = 0; i < params.length; i++) { pstmt.setObject(i + 1, params[i]); } } try (ResultSet rs = pstmt.executeQuery()) { return convertResultSetToList(rs); } } }
调用时更简洁:
List<Map<String, Object>> products = dbUtils.executeQuery(sql, 100, 50);
内容的提问来源于stack exchange,提问作者Alberto Manuguerra
相关产品推荐
相关产品推荐

