简体   繁体   English

Java / JDBC –使用JDBC PreparedStatement的多参数搜索

[英]Java/ JDBC – Multi Parameter Search Using JDBC PreparedStatement

I want to create multi parameter search using JDBC prepared statement so as to prevent SQL injection attack and improve performance. 我想使用JDBC准备语句创建多参数搜索,以防止SQL注入攻击并提高性能。 As I couldn't find the best way to do it on the net. 因为我找不到在网络上执行此操作的最佳方法。

I've tried to implement on my own as follow. 我尝试按照以下方式自行实施。

In this program I want to allow the user to search an employee by either first name, last name or department id. 在此程序中,我希望允许用户按名字,姓氏或部门ID搜索员工。

I want to know 我想知道

  1. if my implementation would prevent SQL injection 如果我的实现会阻止SQL注入
  2. If I am using prepared statement correctly? 如果我正确使用了准备好的语句? I have some doubt on this line 我对此有疑问
    PreparedStatement stat = conn.prepareStatement(sql.toString());

Let's say two users search by using the same parameters, and thus it would result the same sql string. 假设两个用户使用相同的参数进行搜索,因此将产生相同的sql字符串。 According to my implementation, would the database have to prepare that sql twice or just once? 根据我的实现,数据库是否必须准备两次或一次准备该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";
    }

Yes -- as written this will prevent SQL injection attacks and yes, that is how you use .prepareStatement . 是的-如本文所述,这将防止SQL注入攻击,是的,这就是您使用.prepareStatement You should probably post this code on https://codereview.stackexchange.com/ if you want a critique of how it's done. 如果您想对它的完成方式进行评论,则可能应该在https://codereview.stackexchange.com/上发布此代码。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM