Java / JDBC - 使用JDBC PreparedStatement进行多参数搜索

时间:2014-09-04 11:07:20

标签: java jdbc

我想使用JDBC预处理语句创建多参数搜索,以防止SQL注入攻击并提高性能。因为我无法在网上找到最好的方法。

我试图按照自己的方式实施。

在此计划中,我希望允许用户使用名字,姓氏或部门ID搜索员工。

我想知道

  1. 如果我的实现会阻止SQL注入
  2. 如果我正确使用预备声明?我对这一行有一些疑问
  3.     PreparedStatement stat = conn.prepareStatement(sql.toString());
    

    让我们说两个用户使用相同的参数进行搜索,因此结果相同     sql字符串。根据我的实现,数据库是否必须准备两次或只准备一次?

        public class EmpDAO {
    
            public static List<Employee> findByCriteria(Employee e)
                    throws SQLException, IOException {
    
                try (Connection conn = getConnection()) {
    
                    StringBuilder sql = new StringBuilder("SELECT * FROM Employee ");
    
                    //collect user supplied parameters
                    Map<String, String> params = new HashMap<String, String>();
                    if (e.getFname() != null && e.getFname().length() != 0) {
                        params.put(EmpDAO.FNAME, e.getFname());
                    }
                    if (e.getLname() != null && e.getLname().length() != 0) {
                        params.put(EmpDAO.LNAME, e.getLname());
                    }
    
                    if (e.getDepid() > 0) {
                        params.put(EmpDAO.DEPT_ID, new Integer(e.getDepid()).toString());
                    }
    
                    //construct prepared statement based on the parameters
    
                    Set<String> colSet = params.keySet();
                    if (colSet != null && !colSet.isEmpty()) {
                        StringBuilder whereClause = new StringBuilder(" WHERE");
                        String andOp = "";
                        for (String colName : colSet) {                 
                            whereClause.append(andOp);
                            whereClause.append(" ");
                            whereClause.append(colName);
                            whereClause.append("=? ");
                            andOp = " AND ";
                        }
    
                        sql.append(whereClause);
                    }
    
                    PreparedStatement stat = conn.prepareStatement(sql.toString());
                    int paramPos = 1;
                    for (String colName : colSet) {
                        if (colName.equals(EmpDAO.FNAME)) {
                            stat.setString(paramPos, params.get(colName));
                        }
    
                        if (colName.equals(EmpDAO.LNAME)) {
                            stat.setString(paramPos, params.get(colName));
                        }
    
                        if (colName.equals(EmpDAO.DEPT_ID)) {
                            stat.setInt(paramPos, Integer.parseInt(params.get(colName)));
                        }
                        paramPos++;
                    }
    
                    List<Employee> emp1 = new ArrayList<>();
                    try (ResultSet result = stat.executeQuery()) {
    
                        while (result.next()) {
                            Employee emp = new Employee();
                            emp.setDepid(result.getInt("DEPT_ID"));
                            emp.setEmpid(result.getInt("EMP_ID"));
                            emp.setFname(result.getString("FNAME"));
                            emp.setJobid(result.getInt("JOB_ID"));
                            emp.setLname(result.getString("LNAME"));
                            emp.setMangid(result.getInt("MANAGER_EMP_ID"));
                            emp.setSalary(result.getInt("SALARY"));
                            emp1.add(emp);
                        }
                    }
                    return emp1;
                }
            }
    
            public static Connection getConnection() throws SQLException, IOException {
                try {
                    Class.forName("com.mysql.jdbc.Driver");
                } catch (ClassNotFoundException ex) {
                    ex.printStackTrace();
                }
                return DriverManager.getConnection("jdbc:mysql://localhost:3306/test",
                        "root", "root");
            }
    
            public static final String FNAME = "FNAME";
            public static final String LNAME = "FNAME";
            public static final String DEPT_ID = "FNAME";
        }
    

1 个答案:

答案 0 :(得分:0)

是 - 正如所写,这将阻止SQL注入攻击,是的,这就是你使用.prepareStatement的方式。如果您想要批评它是如何完成的,那么您应该在https://codereview.stackexchange.com/上发布此代码。