JDBC-PreparedStatement

JDBC-PreparedStatement

PreparedStatement作用:预编译SQL语句并执行:预防SQL注入问题。
SQL注入:是通过操作输入来修改事先定义好的SQL语句,用以达到执行代码对服务器进行攻击的方法。

/**
     * 演示sql注入
     * @throws SQLException
     */
    @Test
    public void testLogin_Inject() throws SQLException {
        // 1. 注册驱动
        // Class.forName("com.mysql.jdbc.Driver");

        // 2. 获取连接
        //String url = "jdbc:mysql:///db1";
        String url = "jdbc:mysql:///db2?useSSL=false";  // 禁用安全连接警告
        String username = "root";
        String password = "1234";
        Connection conn = DriverManager.getConnection(url, username, password);

        // 接收用户名和密码
        String name = "dgdgdfgdf";
        String pwd = "' or '1' = '1";

        String sql = "SELECT * FROM tb_user WHERE username='" + name + "' and password = '" + pwd + "'";
        System.out.println(sql);
        // SELECT * FROM tb_user WHERE username='dgdgdfgdf' and password = '' or '1' = '1'

        // 获取stmt对象
        Statement stmt = conn.createStatement();

        // 执行sql
        ResultSet rs = stmt.executeQuery(sql);

        // 判断是否登录成功
        if (rs.next()) {
            System.out.println("登录成功~");
        } else {
            System.out.println("登录失败~");
        }


        // 7. 释放资源
        /*rs.close();
        stmt.close();
        conn.close();*/
    }

步骤

  1. 获取PreparedStatement对象

    //SQL语句中的参数值,使用?占位符替代
    String sql = "SELECT * FROM user WHERE username=? and password=?";
    // 通过Connection对象获取,并传入对应的sql语句
    PreparedStatement pstmt = conn.preparedStatement(sql);
    
  2. 设置参数值

    PreparedStatement对象:setXxx(参数1, 参数2): 给?赋值
    Xxx: 数据类型;如setInt(参数1, 参数2)
    参数:
        参数1:?的位置编号,从1开始
        参数2:?的值
    
  3. 执行SQL

    executeUpdate(); / executeQuery(); 不需要再传递sql
    

演示

/**
     * 预编译SQL的演示
     *
     * @throws SQLException
     */
    @Test
    public void testLogin() throws SQLException {
        // 1. 注册驱动
        // Class.forName("com.mysql.jdbc.Driver");

        // 2. 获取连接
        //String url = "jdbc:mysql:///db1";
        String url = "jdbc:mysql:///db2?useSSL=false";  // 禁用安全连接警告
        String username = "root";
        String password = "1234";
        Connection conn = DriverManager.getConnection(url, username, password);

        // 接收用户名和密码
        String name = "zhangsan";
        // String pwd = "dfghkdf";
        String pwd = "' or '1' = '1";

        // 定义sql
        String sql = "SELECT * FROM tb_user WHERE username = ? and password = ?";

        // 获取pstmt对象
        PreparedStatement pstmt = conn.prepareStatement(sql);

        // 设置?的值
        pstmt.setString(1, name);
        pstmt.setString(2, pwd);
        // 防止注入前的sql语句为:
        // SELECT * FROM tb_user WHERE username = 'zhangsan' AND password = '' or '1' = '1''
        //最终的sql语句被转义
        // SELECT * FROM tb_user WHERE username = 'zhangsan' AND password = '\' or \'1\' = \'1'

        // 执行sql
        ResultSet rs = pstmt.executeQuery();

        // 判断是否登录成功
        if (rs.next()) {
            System.out.println("登录成功~");
        } else {
            System.out.println("登录失败~");
        }


        // 7. 释放资源
        /*rs.close();
        stmt.close();
        conn.close();*/
    }

PreparedStatement原理

  1. PreparedStatement预编译功能开启:useServerPrepStmts=true
  2. 配置MySQL执行日志(重启MySQL服务器后生效)
log-output=FILE
general-log=1
general_log_file="D:\mysql.log"
slow-query_log_file="D:\mysql_slow.log"
long_query_time=2