该对象有Connection对象的方法prepareStatement(String sql) 返回
PreparedStatement:执行sql的对象
一、继承结构与作用
PreparedStatement是Statement接口的子接口,继承于父接口中所有的方法。它是一个预编译的SQL语句
作用:
1) 因为有预先编译的功能,提高SQL的执行效率。
2) 可以有效的防止SQL注入的问题,安全性更高。
二、执行原理
三、PreparedStatement接口中的方法
方法 | 描述 |
int executeUpdate() | 执行DML,增删改的操作,返回影响的行数。 |
ResultSet executeQuery() | 执行DQL,查询的操作,返回结果集 |
四、PreparedSatement的好处
1.prepareStatement()会先将SQL语句发送给数据库预编译。PreparedStatement会引用着预编译后的结果。可以多次传入不同的参数给PreparedStatement对象并执行。减少SQL编译次数,提高效率。
2.安全性更高,没有SQL注入的隐患。
3.提高了程序的可读性
五、注入问题
1. SQL注入问题:在拼接sql时,有一些sql的特殊关键字参与字符串的拼接。会造成安全性问题
(1). 输入用户随便,输入密码:a' or 'a' = 'a
(2). sql:select * from user where username = 'fhdsjkf' and password = 'a' or 'a' = 'a'
2. 解决sql注入问题:使用PreparedStatement对象来解决
3. 预编译的SQL:参数使用?作为占位符
4. 步骤:
(1). 导入驱动jar包 mysql-connector-java-5.1.37-bin.jar
(2). 注册驱动
(3). 获取数据库连接对象 Connection
(4). 定义sql
* 注意:sql的参数使用?作为占位符。 如:select * from user where username = ? and password = ?;
(5). 获取执行sql语句的对象 PreparedStatement Connection.prepareStatement(String sql)
(6). 给?赋值:
* 方法: setXxx(参数1,参数2)
* 参数1:?的位置编号 从1 开始
* 参数2:?的值
(7). 执行sql,接受返回结果,不需要传递sql语句
(8). 处理结果
(9). 释放资源
5. 注意:后期都会使用PreparedStatement来完成增删改查的所有操作
1. 可以防止SQL注入
2. 效率更高
六、案例演示
注意:实现需要在mysql建立一个用户数据表,并输入一定的数据进行测试
在mySQL中输入如下命令:
create table user (
id int primary key auto_increment,
name varchar(20),
password varchar(20)
)
insert into user values (null,'jack','123'),(null,'rose','456');
-- 登录, SQL中大小写不敏感
select * from user where name='JACK' and password='123';
-- 登录失败
select * from user where name='JACK' and password='333';
转存失败重新上传取消
案例一:存在注入问题的程序,(本质就是输入特殊字符,让JAVA组成特殊判断语句,判断结果一定为true)
用户通过提示信息输入用户名和密码
import com.net.lwgk.util.JDBCUtils;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Scanner;
/*
使用Statement存在注入问题
*/
public class Demo07JDBC {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("请输入用户名:");
String user = sc.next();
System.out.println("请输入密码");
String password = sc.next();
boolean isRet = new Demo07JDBC().login(user,password);
if(isRet){
System.out.println("登录成功");
}else{
System.out.println("登录失败");
}
}
/**
*
* @param user_sc
* @param password_sc
*/
public boolean login(String user_sc,String password_sc){
if (user_sc ==null || password_sc==null){
return false;
}
Connection conn = null;
Statement stmt = null;
ResultSet resSet = null;
try {
conn = JDBCUtils.getConnection();
stmt = conn.createStatement();
String sql = "select * from user where user ='"+user_sc+"' and password = '"+password_sc+"' ";
System.out.println(sql);
resSet = stmt.executeQuery(sql);
return resSet.next();
} catch (SQLException e) {
e.printStackTrace();
}finally {
JDBCUtils.close(resSet,stmt,conn);
}
return false;
}
}
转存失败重新上传取消
测试注入问题:
请输入用户名:
sdfsdfsdf
请输入密码
a' or '1'='1
select * from user where user ='sdfsdfsdf' and password ='a' or '1'='1'
登录成功
转存失败重新上传取消
问题分析:
select * from user where name='newboy' and password='a' or '1'='1'
name='newboy' and password='a' 为假
'1'='1' 真
相当于
select * from user where true; 查询了所有记录
转存失败重新上传取消
案例二:规避注入问题:
import com.net.lwgk.util.JDBCUtils;
import java.sql.*;
import java.util.Scanner;
/*
使用Statement存在注入问题
*/
public class Demo08JDBC {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("请输入用户名:");
String user = sc.next();
System.out.println("请输入密码");
String password = sc.next();
boolean isRet = new Demo08JDBC().login(user,password);
if(isRet){
System.out.println("登录成功");
}else{
System.out.println("登录失败");
}
}
/**
*
* @param user_sc
* @param password_sc
*/
public boolean login(String user_sc,String password_sc){
if (user_sc ==null || password_sc==null){
return false;
}
Connection conn = null;
PreparedStatement stmt = null;
ResultSet resSet = null;
try {
conn = JDBCUtils.getConnection();
String sql = "select * from user where user=? and password = ? ";
//获取执行sql对象
stmt = conn.prepareStatement(sql);
//给?赋值
stmt.setString(1,user_sc);
stmt.setString(2,password_sc);
//执行SQL
resSet = stmt.executeQuery();
return resSet.next();
} catch (SQLException e) {
e.printStackTrace();
}finally {
JDBCUtils.close(resSet,stmt,conn);
}
return false;
}
}
转存失败重新上传取消