JDBC系列教材 (五)- 在JDBC中使用预编译Statement 以及它的优点

步骤1:使用PreparedStatement
步骤2:PreparedStatement的优点1-参数设置
步骤3:PreparedStatement的优点2-性能表现
步骤4:PreparedStatement的优点3-防止SQL注入式攻击
步骤5:练习-性能比较
步骤6:答案-性能比较

步骤 1 : 使用PreparedStatement

和 Statement一样,PreparedStatement也是用来执行sql语句的
与创建Statement不同的是,需要根据sql语句创建PreparedStatement
除此之外,还能够通过设置参数,指定相应的值,而不是Statement那样使用字符串拼接

注: 这是JAVA里唯二的基1的地方,另一个是查询语句中的ResultSet也是基1的。

package jdbc;

    

import java.sql.Connection;

import java.sql.DriverManager;

import java.sql.PreparedStatement;

import java.sql.SQLException;

    

public class TestJDBC {

    public static void main(String[] args) {

        try {

            Class.forName("com.mysql.jdbc.Driver");

        catch (ClassNotFoundException e) {

            e.printStackTrace();

        }

  

        String sql = "insert into hero values(null,?,?,?)";

        try (Connection c = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/how2java?characterEncoding=UTF-8","root""admin");

            // 根据sql语句创建PreparedStatement

            PreparedStatement ps = c.prepareStatement(sql);

        ) {

             

            // 设置参数

            ps.setString(1"提莫");

            ps.setFloat(2313.0f);

            ps.setInt(350);

            // 执行

            ps.execute();

  

        catch (SQLException e) {

            // TODO Auto-generated catch block

            e.printStackTrace();

        }

    

    }

}

步骤 2 : PreparedStatement的优点1-参数设置

Statement 需要进行字符串拼接,可读性和维护性比较差

String sql = "insert into hero values(null,"+"'提莫'"+","+313.0f+","+50+")";


PreparedStatement 使用参数设置,可读性好,不易犯错

String sql = "insert into hero values(null,?,?,?)";

package jdbc;

  

import java.sql.Connection;

import java.sql.DriverManager;

import java.sql.PreparedStatement;

import java.sql.SQLException;

import java.sql.Statement;

  

public class TestJDBC {

    public static void main(String[] args) {

  

        try {

            Class.forName("com.mysql.jdbc.Driver");

        catch (ClassNotFoundException e) {

            e.printStackTrace();

        }

  

        String sql = "insert into hero values(null,?,?,?)";

        try (Connection c = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/how2java?characterEncoding=UTF-8","root""admin"); 

            Statement s = c.createStatement(); 

            PreparedStatement ps = c.prepareStatement(sql);

        ) {

            // Statement需要进行字符串拼接,可读性和维修性比较差

            String sql0 = "insert into hero values(null," "'提莫'" "," 313.0f + "," 50")";

            s.execute(sql0);

  

            // PreparedStatement 使用参数设置,可读性好,不易犯错

            // "insert into hero values(null,?,?,?)";

            ps.setString(1"提莫");

            ps.setFloat(2313.0f);

            ps.setInt(350);

            ps.execute();

        catch (SQLException e) {

            // TODO Auto-generated catch block

            e.printStackTrace();

        }

  

    }

}

步骤 3 : PreparedStatement的优点2-性能表现

PreparedStatement有预编译机制,性能比Statement更快

package jdbc;

  

import java.sql.Connection;

import java.sql.DriverManager;

import java.sql.PreparedStatement;

import java.sql.SQLException;

import java.sql.Statement;

  

public class TestJDBC {

    public static void main(String[] args) {

  

        try {

            Class.forName("com.mysql.jdbc.Driver");

        catch (ClassNotFoundException e) {

            e.printStackTrace();

        }

  

        String sql = "insert into hero values(null,?,?,?)";

        try (Connection c = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/how2java?characterEncoding=UTF-8","root""admin"); 

                Statement s = c.createStatement(); 

                PreparedStatement ps = c.prepareStatement(sql);

            ) {

            // Statement执行10次,需要10次把SQL语句传输到数据库端

            // 数据库要对每一次来的SQL语句进行编译处理

            for (int i = 0; i < 10; i++) {

                String sql0 = "insert into hero values(null," "'提莫'" ","

                        313.0f + "," 50 ")";

                s.execute(sql0);

            }

            s.close();

  

            // PreparedStatement 执行10次,只需要1次把SQL语句传输到数据库端

            // 数据库对带?的SQL进行预编译

  

            // 每次执行,只需要传输参数到数据库端

            // 1. 网络传输量比Statement更小

            // 2. 数据库不需要再进行编译,响应更快

            for (int i = 0; i < 10; i++) {

                ps.setString(1"提莫");

                ps.setFloat(2313.0f);

                ps.setInt(350);

                ps.execute();

            }

        catch (SQLException e) {

            // TODO Auto-generated catch block

            e.printStackTrace();

        }

  

    }

}

步骤 4 : PreparedStatement的优点3-防止SQL注入式攻击

假设name是用户提交来的数据

String name = "'盖伦' OR 1=1";


使用Statement就需要进行字符串拼接
拼接出来的语句是:

select * from hero where name = '盖伦' OR 1=1


因为有OR 1=1,这是恒成立的
那么就会把所有的英雄都查出来,而不只是盖伦
如果Hero表里的数据是海量的,比如几百万条,把这个表里的数据全部查出来
会让数据库负载变高,CPU100%,内存消耗光,响应变得极其缓慢

而PreparedStatement使用的是参数设置,就不会有这个问题

package jdbc;

  

import java.sql.Connection;

import java.sql.DriverManager;

import java.sql.PreparedStatement;

import java.sql.ResultSet;

import java.sql.SQLException;

import java.sql.Statement;

  

public class TestJDBC {

    public static void main(String[] args) {

  

        try {

            Class.forName("com.mysql.jdbc.Driver");

        catch (ClassNotFoundException e) {

            e.printStackTrace();

        }

  

        String sql = "select * from hero where name = ?";

        try (Connection c = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/how2java?characterEncoding=UTF-8","root""admin");

                Statement s = c.createStatement();

            PreparedStatement ps = c.prepareStatement(sql);

        ) {

            // 假设name是用户提交来的数据

            String name = "'盖伦' OR 1=1";

            String sql0 = "select * from hero where name = " + name;

            // 拼接出来的SQL语句就是

            // select * from hero where name = '盖伦' OR 1=1

            // 因为有OR 1=1,所以恒成立

            // 那么就会把所有的英雄都查出来,而不只是盖伦

            // 如果Hero表里的数据是海量的,比如几百万条,把这个表里的数据全部查出来

            // 会让数据库负载变高,CPU100%,内存消耗光,响应变得极其缓慢

            System.out.println(sql0);

  

            ResultSet rs0 = s.executeQuery(sql0);

            while (rs0.next()) {

                String heroName = rs0.getString("name");

                System.out.println(heroName);

            }

  

            s.execute(sql0);

  

            // 使用预编译Statement就可以杜绝SQL注入

  

            ps.setString(1, name);

  

            ResultSet rs = ps.executeQuery();

            // 查不出数据出来

            while (rs.next()) {

                String heroName = rs.getString("name");

                System.out.println(heroName);

            }

        catch (SQLException e) {

            // TODO Auto-generated catch block

            e.printStackTrace();

        }

  

    }

}


更多内容,点击了解: https://how2j.cn/k/jdbc/jdbc-preparedstatement/388.html

原文地址:https://www.cnblogs.com/Lanht/p/12615465.html