• Java自学-JDBC 预编译PreparedStatement


    在JDBC中使用预编译PreparedStatement 以及它的优点

    步骤 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(2, 313.0f);
                ps.setInt(3, 50);
                // 执行
                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(2, 313.0f);
                ps.setInt(3, 50);
                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(2, 313.0f);
                    ps.setInt(3, 50);
                    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();
            }
      
        }
    }
    

    更多内容,点击了解: 在JDBC中使用预编译PreparedStatement 以及它的优点

  • 相关阅读:
    软工2021个人阅读作业#2——构建之法和CI/CD的运用
    2021年.Net中级开发工程师面试题
    OneForAll框架搭建之旅:Vue + .NetCore WebApi(3)
    创建WebService服务--.NET Core与SoapCore 及遇到的问题(二)
    创建WebService服务--.NET Framework(一)
    面试小记
    Vue开发环境安装
    java笔记之设计模式 1、创建型模式:工厂方法
    Abp太重了?轻量化Abp框架
    Tomcat学习2:一键启动以及源码阅读
  • 原文地址:https://www.cnblogs.com/jeddzd/p/13121451.html
Copyright © 2020-2023  润新知