PreparedStatement
PreparedStatement继承自Statement,表示预编译SQL语句的对象
-
PreparedStatement作用:预编译SQL语句并执行,预防SQL注入问题
SQL注入:是通过操作输入来修改事先预定义好的SQL语句,用以达到执行代码对服务器进行攻击的方法
登录验证操作
import java.sql.*;
public class login {
public static void main(String[] args) throws Exception {
Class.forName("com.mysql.cj.jdbc.Driver");
String url = "jdbc:mysql://127.0.0.1:3306/school?useSSL = false";
String username = "root";
String password = "ZZXQJL@0916.com";
Connection coon = DriverManager.getConnection(url, username, password);
//账户表已存储对应数据
String loginName = "zs";
String loginPassword = "123";
//在双引号里面先使用单引号,再往单引号中使用双引号实现引号的嵌套,中间再使用++,就可以进行字符串和变量的拼接操作
//在这里,sql语句获取用户输入的账号和密码同数据库中的数据进行匹配以判断是否可以登录
String sql = "select * from login where loginname = '"+loginName+"' and loginpassword = '"+loginPassword+"'; ";
//获取stmt对象
Statement stmt = coon.createStatement();
//执行SQL
ResultSet rs = stmt.executeQuery(sql);
//判断登录是否成功
if (rs.next()){
System.out.println("登陆成功");
}else{
System.out.println("登录失败");
}
rs.close();
stmt.close();
coon.close();
}
}
演示SQL注入:
输入任意的字符串为账户名,密码输入为 ' or '1' = '1
String loginName = "zsdasdad"; String loginPassword = "' or '1' = '1"; String sql = "select * from login where loginname = '"+loginName+"' and loginpassword = '"+loginPassword+"'; "; //登录成功
原因:
SQL注入后,原DQL语句变成了
select * from login where loginName = 'zsdasdad' and loginPassword = '' or '1' = '1';
该SQL执行时,loginName和loginPassword被and连接,此时loginPassword的值为空字符串,使得and前后两个值都不成立,使最终的and逻辑值为False,此时or后为一个恒等式,逻辑值为True,使得最终的逻辑运算为False or True ,结果即为True,使得即使密码账号错误,依然可以获取login表中的所有信息
解决SQL注入问题
需求:完成用户登录
select * from tb_user where username = 'zhangsan' and password = '123';
PreparedStatement作用:预编译SQL并执行SQL语句
执行流程:
-
获取PreparedStatement对象
//SQL语句中的参数值,使用 ? 占位符替代 String sql = "select * from tb_user where username = ? and password = ?";
-
设置参数值
PreparedStatement对象:setXxx(参数1,参数2):给?赋值 Xxx:数据类型;如setInt(参数1,参数2) 参数1:?的位置编号,从1开始 参数2:?的值
-
执行SQL
executeUpdate(); //或者 executeQuery(); //3.执行SQL,此时括号里面不用再传入S
演示解决SQL注入
String name = "zhangsan"; String password = "abcd"; //定义sql String sql = "select * from tb_user where username = ? and password = ?"; //获取pstmt对象 PreparedStatement pstmt = conn.prepareStatement(sql); //设置 ? 的值 pstmt.setString(1,name); pstmt.setString(2,password); //执行sql ResultSet rs = pstmt.executeQuery(); //判断登录是否成功 if (rs.next()){ System.out.println("登陆成功"); }else{ System.out.println("登录失败"); } rs.close(); pstmt.close(); coon.close();
PreparedStatement原理
优点:
-
预编译SQL,性能更高
-
防止SQL注入,将敏感字符进行转义
PreparedStatement原理
- 在获取PreparedStatemet对象时,将sql语句发送给MySQL服务器进行检查,编译(这些工作很耗时)
- 执行时不用做上述步骤,速度更快
- 如果SQL模板一样,则只需要进行一次检查,编译
PreparedStatement预编译功能默认是关闭状态,需要主动开启
useServerPrepStmts = true
// String url = "jdbc:mysql://127.0.0.1:3306/school?useSSL = false&useServerPrepStmts = true";
网友评论