javaweb学习笔记之JDBC预编译与sql注入问题

什么是sql注入

我们写一个登录的界面,把密码设为fdsa和1,代码如下

select * from tbl_user where username = 'fdsafds' and password = 'fdsa' or '1'='1'; 

当我们输入

用户名:fdsafds
密码:fdsa' or '1'='1
这样可以登录成功,为什么?

以上SQL语句where条件恒成立,会将数据库表当中的数据全部查询出来
以上现象被称为SQL注入,即

    当用户提供的信息当中含有SQL语句的关键字,并且这些关键字参与了SQL语句的编译过程,导致原先的SQL语句原意被扭曲。
    根本原因:先拼接SQL语句,再进行编译,这是根本原因。

我们如何看待SQL注入

SQL注入不一定是一种危害,但大多数情况下会危及系统的安全,有一些系统中的特殊功能可能还需要SQL注入功能。
此时为了支持SQL注入,需要使用java.sql.Statement接口。

怎么解决SQL注入,或者说怎么防止SQL注入?

java.sql.PreparedStatement叫做预编译的数据库操作对象,可以防止SQL注入,
原理:

对SQL语句框架进行预先编译,再接收用户提供的信息,即使提供的信息当中含有SQL语句的关键字,但是这些关键字并没有参与SQL语句的编译,
那么它也只是一个普通的字符串,SQL语句原意不会被扭曲,防止了SQL注入。

PreparedStatement是Statement的子接口

大多数情况下还是需要防止SQL注入的,所以PreparedStatement使用较多。

Statement和PreparedStatement区别

1.	Statement是先进行SQL语句拼接,再进行SQL语句的编译,存在SQL注入问题;
2.	PreparedStatement是预先编译SQL语句框架(带有占位符的SQL),然后再给占位符赋值,防止SQL注入;
3.	Statement编译一次,执行一次,编译一次,执行一次,PreparedStatement编译一次框架,执行N次,
4.	PreparedStatement效率较高。

预编译实现批量处理

当我们需要处理一百条甚至更多数据时,如果我们采用原始的处理方法:

for(int i=1;i<=100;i++){
    
    
            String sql="insert into dept(deptno,dname,loc) values("+i+",'dept_"+i+"','北京')";
            ps.executeUpdate(sql);
        }

我们可以看到有以下问题:

  1. SQL命令书写麻烦:
    为了确保每条SQL语句携带不同数据,采用字符串拼接方式
    “insert into dept(deptno,dname,loc) values(”+i+",‘dept_"+i+"’,‘北京’)";

  2. 浪费时间: PreparedStatement对象每次只能推送一条SQL命令。
    为了推送100条Sql命令,需要往返100次,浪费了大量时间

我们可以看到,上面的程序对于程序员来说简直烂透了
对于这种批量处理问题,我们采取预编译的方法形式SQL命令:

    "?"是占位符,一个问号代替一个值
    预编译SQL相当一个模具,在后续开发时,只需要将数据填充到占位符,就可以得到一个全新SQL
String sql ="insert into dept(deptno,dname,loc) values(?,?,?)";
    //注册Driver
  Class.forName("com.mysql.jdbc.Driver");
    //建立通道
   Connection con = DriverManager.getConnection("jdbc:mysql://localhost:3306/bjpowernode", "root", "123");
    //【建立交通工具时,需要将预编译SQL命令注册到PreparedStatement】
    PreparedStatement ps =  con.prepareStatement(sql);

//通过向预编译SQL命令填充数据生成全新的SQL命令

 //4.向MySql服务器推送100条数据
        for(int i=1;i<=100;i++){
    
    
          
            ps.setInt(1, i); //inser into dept (deptno,dname,loc) values(1,?,?)
            ps.setString(2, "dept_"+i); //inser into dept (deptno,dname,loc) values(1,'dept_1',?)
            ps.setString(3, "北京");//inser into dept (deptno,dname,loc) values(1,'dept_1','北京')
            //在新的SQL语句生成之后,将SQL语句作为子弹添加到PS的弹夹
            ps.addBatch(); //[sql1,sql2,...]
        }

Java 的 Statement.addBath() 方法将给定的 SQL 命令添加到此 Statement 对象的当前命令列表中。通过调用方法 executeBatch 可以批量执行此列表中的命令。
【一次性】通过ps将100条sql语句推送到mysql服务器执行

   ps.executeBatch(); // 推送100条SQL命令只需要往返一次

然后我们在关闭之前建立的资源就可以了。

猜你喜欢

转载自blog.csdn.net/qq_47917118/article/details/115269293