JDBC中为PreparedStatement设置多个参数有没有更简洁高效的方法?
你示例中的INSERT SQL语句存在语法问题,VALUES括号内最后一个占位符后多写了逗号,需要先删掉避免执行报错。
下面是两种高效简化PreparedStatement参数绑定的方案:
方案1:封装通用参数设置工具(最常用,无额外依赖)
可以封装一个通用的JDBC工具方法,不用每次手动按下标调用对应类型的set方法,代码量直接减少一半以上:
public class JdbcUtils { /** * 按顺序给PreparedStatement设置参数 * @param ps 预编译语句对象 * @param params 按SQL占位符顺序传入的参数值 * @throws SQLException 参数设置异常 */ public static void setParams(PreparedStatement ps, Object... params) throws SQLException { for (int i = 0; i < params.length; i++) { // JDBC的setObject会自动适配绝大多数常见SQL类型(int、String、Float、Timestamp等都支持) ps.setObject(i + 1, params[i]); } } }
改造后的业务代码参数绑定部分只需要一行:
public void create(FilmBean film) { String queryString = "Insert INTO film(film_id, title, description, release_year, language_id, original_language_id," + " rental_duration, rental_rate, length, replacement_cost, rating, special_features, last_update) VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?)"; try { connection = getConnection(); ptmt = connection.prepareStatement(queryString); // 直接按SQL占位符顺序传参数即可,不用数下标、不用写对应类型的set方法 JdbcUtils.setParams(ptmt, film.getFilmId(), film.getFilmTitle(), film.getDescription(), film.getReleaseYear(), film.getLanguageId(), film.getOriginalLanguageId(), film.getRentalDuration(), film.getRentalRate(), film.getLength(), film.getReplacementCost(), film.getRating(), film.getSpecialFeatures(), film.getLastUpdate() ); ptmt.executeUpdate(); System.out.println("Data Added Successfully"); } catch (SQLException e) { e.printStackTrace(); } finally { try { if (ptmt != null) ptmt.close(); if (connection != null) connection.close(); } catch (SQLException e) { e.printStackTrace(); } } }
方案2:反射自动绑定(适合字段极多,实体类和表字段对应度高的场景)
如果实体类属性名和表字段名可以一一对应,可以用反射实现完全自动的参数绑定,连手动写get方法的步骤都省了:
public class JdbcUtils { /** * 按指定字段顺序从实体类读取值绑定到PreparedStatement * @param ps 预编译语句对象 * @param entity 实体类对象 * @param fieldOrder SQL占位符对应的实体类属性名,顺序必须和SQL占位符顺序完全一致 * @throws Exception 反射或参数设置异常 */ public static void setParamsByEntity(PreparedStatement ps, Object entity, List<String> fieldOrder) throws Exception { BeanInfo beanInfo = Introspector.getBeanInfo(entity.getClass()); Map<String, Method> getterMap = new HashMap<>(); for (PropertyDescriptor pd : beanInfo.getPropertyDescriptors()) { getterMap.put(pd.getName(), pd.getReadMethod()); } for (int i = 0; i < fieldOrder.size(); i++) { Object value = getterMap.get(fieldOrder.get(i)).invoke(entity); ps.setObject(i + 1, value); } } }
使用方式:
// 提前定义好INSERT语句对应的实体类属性顺序,全局复用即可 private static final List<String> FILM_INSERT_FIELD_ORDER = Arrays.asList( "filmId", "filmTitle", "description", "releaseYear", "languageId", "originalLanguageId", "rentalDuration", "rentalRate", "length", "replacementCost", "rating", "specialFeatures", "lastUpdate" ); public void create(FilmBean film) { String queryString = "Insert INTO film(film_id, title, description, release_year, language_id, original_language_id," + " rental_duration, rental_rate, length, replacement_cost, rating, special_features, last_update) VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?)"; try { connection = getConnection(); ptmt = connection.prepareStatement(queryString); // 一行完成参数绑定,不用写任何get方法 JdbcUtils.setParamsByEntity(ptmt, film, FILM_INSERT_FIELD_ORDER); ptmt.executeUpdate(); System.out.println("Data Added Successfully"); } catch (Exception e) { e.printStackTrace(); } finally { try { if (ptmt != null) ptmt.close(); if (connection != null) connection.close(); } catch (SQLException e) { e.printStackTrace(); } } }
额外优化建议
可以用Java 7及以上版本支持的try-with-resources语法自动关闭资源,不需要手动写finally块关闭连接和PreparedStatement,代码更简洁:
public void create(FilmBean film) { String queryString = "Insert INTO film(film_id, title, description, release_year, language_id, original_language_id," + " rental_duration, rental_rate, length, replacement_cost, rating, special_features, last_update) VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?)"; // 括号内定义的资源会在try块执行结束后自动关闭 try (Connection connection = getConnection(); PreparedStatement ptmt = connection.prepareStatement(queryString)) { JdbcUtils.setParams(ptmt, film.getFilmId(), film.getFilmTitle(), film.getDescription(), film.getReleaseYear(), film.getLanguageId(), film.getOriginalLanguageId(), film.getRentalDuration(), film.getRentalRate(), film.getLength(), film.getReplacementCost(), film.getRating(), film.getSpecialFeatures(), film.getLastUpdate() ); ptmt.executeUpdate(); System.out.println("Data Added Successfully"); } catch (SQLException e) { e.printStackTrace(); } }
内容的提问来源于stack exchange,提问作者Filippo Scalvedi
相关产品推荐
相关产品推荐

