我们写一个登录的界面,把密码设为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注入,需要使用java.sql.Statement接口。
java.sql.PreparedStatement叫做预编译的数据库操作对象,可以防止SQL注入,
原理:
对SQL语句框架进行预先编译,再接收用户提供的信息,即使提供的信息当中含有SQL语句的关键字,但是这些关键字并没有参与SQL语句的编译,
那么它也只是一个普通的字符串,SQL语句原意不会被扭曲,防止了SQL注入。
PreparedStatement是Statement的子接口
大多数情况下还是需要防止SQL注入的,所以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);
}
我们可以看到有以下问题:
SQL命令书写麻烦:
为了确保每条SQL语句携带不同数据,采用字符串拼接方式
“insert into dept(deptno,dname,loc) values(”+i+",‘dept_"+i+"’,‘北京’)";
浪费时间: 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命令只需要往返一次
然后我们在关闭之前建立的资源就可以了。