HikariCP 参数化查询


在【HikariCP简单使用】中,我们都是使用的自己拼写的SQL语句,而通过字符串连接产生的SQL语句,都可能会导致 SQL注入 的发生。
SQL注入:
在字符串拼接的时候,用户输入的部分,用户恶意的输入了字符串 导致非预期的结果。
比如: select * from user where username = 'tom'
tom 应该是用户输入的字符串,假如用户恶意输入 tom ' or '1'='1
则拼接后的字符串为 select * from user where username = ' tom' or '1'='1'
则会将所有结果查询出来,如果恶意输入 delete 语句,后果则不堪设想。
参数化查询
参数化查询是解决SQL注入漏洞的好办法。
参数化的新增
/* 新增-参数化 */ public static int add_demo_with_param() { int result = -1; try { HikariDataSource dataSource = getDataSource(); Connection connection = dataSource.getConnection(); String sql = "insert user values(NULL,?,?,?)"; PreparedStatement statement = connection.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS); statement.setObject(1, "10"); statement.setObject(2, "10"); statement.setObject(3, 0); statement.execute(); ResultSet resultSet = statement.getGeneratedKeys(); if (resultSet != null) { if (resultSet.next()) result = resultSet.getInt(1); } if (connection != null && !connection.isClosed()) connection.close(); if (dataSource != null && !dataSource.isClosed()) dataSource.close(); } catch (Exception e) { e.printStackTrace(); } return result; }
在参数化查询中,不再是 Connection 直接 CreateStatement,而是先 prepareStatement 先准备一个 Statement,然后再为参数赋值。
参数化更新
/*参数化更新*/ public static int update_demo_with_param() { try { HikariDataSource dataSource = getDataSource(); Connection connection = dataSource.getConnection(); String sql = "update user set username = ? where userid = ?"; PreparedStatement statement = connection.prepareStatement(sql); statement.setObject(1, "changed"); statement.setObject(2, 5); return statement.executeUpdate(); } catch (Exception e) { e.printStackTrace(); } return -1; }
参数化查询
public static ResultSet queryDemo() { try { /* HikariDataSource 是需要关闭的 */ HikariDataSource dataSource = getDataSource(); Connection connection = dataSource.getConnection(); String sql = "select * from user where usercode = ?"; PreparedStatement statement = connection.prepareStatement(sql); statement.setObject(1, "admin"); ResultSet resultSet = statement.executeQuery(); if (connection != null && !connection.isClosed()) connection.close(); if (dataSource != null && !dataSource.isClosed()) dataSource.close(); return resultSet; } catch (Exception e) { e.printStackTrace(); } return null; }
ResultSet 和 List<T> 的转化
上面的参数化查询,其实不应该返回 ResultSet,连接关闭后,ResultSet也不能访问了,将返回的 ResultSet 集合转成对应的 List<T> 才是不错的。
那如何转换呢,我们主要用到了 反射 的方法。
public static <T> List<T> toList(ResultSet resultSet, Class<T> type) throws SQLException, InstantiationException, IllegalAccessException, NoSuchFieldException, SecurityException { List<T> list = new ArrayList<T>(); if (resultSet != null) { ResultSetMetaData md = resultSet.getMetaData();// 获取键名 int columnCount = md.getColumnCount();// 获取行的数量 while (resultSet.next()) { // 此类要有默认的构造函数 T instance = type.newInstance(); Field[] fields = type.getDeclaredFields(); for (int i = 1; i <= columnCount; i++) { String colName = md.getColumnName(i); Object val = resultSet.getObject(i); for (Field field : fields) { if (field.getName().equalsIgnoreCase(colName)) { field.setAccessible(true); field.set(instance, val); } } } list.add(instance); } } return list; }
ResultSet 和 List<HashMap<String, String>> 的转化
public List<HashMap<String, String>> toListHashMap(ResultSet rs) throws SQLException { if (rs == null) return null; List<HashMap<String, String>> result = new ArrayList<HashMap<String, String>>(); HashMap<String, String> map = new HashMap<String, String>(); ResultSetMetaData md = rs.getMetaData(); // 得到结果集的结构信息,比如字段数、字段名等 int columnCount = md.getColumnCount(); // 返回此 ResultSet 对象中的列数 while (rs.next()) { map = new HashMap<String, String>(columnCount); for (int i = 1; i <= columnCount; i++) { map.put(md.getColumnName(i), String.valueOf(rs.getObject(i))); } result.add(map); } return result; }
总体来说,参数化的方法比较简单,不管是新增,还是更新或查询,都是先准备一个 Statement,然后再为其变量赋值。
版权说明
作者:SQBER
本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
{0}
{5}
{1}
{2}回复
{4}
*昵称:
*邮箱:
个人站点:
*想说的话: