目錄
文章相關視頻出處:https://developer.aliyun.com/lesson_1694_13598?spm=5176.10731542.0.0.4a023fdbjxoV5w#_13598
一PrepareStatement使用
主要特點:防止sql注入、提升效率
當前數據庫:
代碼:
package jdbc;
import org.junit.Test;
import java.sql.*;
/**
* Created by kevin on 2020/3/23.
*/
public class Demo3 {
public boolean login(String name,String password){
/**
* 一、Connection
* 二、Statement
* 三、ResultSet
*/
Connection connection = null;
Statement statement = null;
ResultSet resultSet = null;
try {
String driverClassName = "com.mysql.cj.jdbc.Driver";
String url = "jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC";
String mysqlUserName="root";
String mysqlPassword="mysql";
Class.forName(driverClassName);
connection = DriverManager.getConnection(url,mysqlUserName,mysqlPassword);
statement = connection.createStatement();
String sql = "select * from stu WHERE name = '"+name+"'and password = '"+password+"'";
resultSet = statement.executeQuery(sql);
return resultSet.next();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if(resultSet!=null){
resultSet.close();
}
if(statement!=null){
statement.close();
}
if(connection!=null){
connection.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
return false;
}
@Test
public void fun1(){
String userName= "張三";
String password="111111";
String userName2= "錯名' or 'a'='a";
String password2="錯密碼' or 'a'='a";
//正常輸入
System.out.println(login(userName,password));
//sql注入越過正常邏輯判斷
System.out.println(login(userName2,password2));
}
}
輸出
通過PrepareStatement方式新建login2方法
public boolean login2(String name,String password){
/**
* 一、Connection
* 二、Statement
* 三、ResultSet
*/
Connection connection = null;
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
try {
String driverClassName = "com.mysql.cj.jdbc.Driver";
String url = "jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC";
String mysqlUserName="root";
String mysqlPassword="mysql";
Class.forName(driverClassName);
connection = DriverManager.getConnection(url,mysqlUserName,mysqlPassword);
// statement = connection.createStatement();
// String sql = "select * from stu WHERE name = '"+name+"'and password = '"+password+"'";
// resultSet = statement.executeQuery(sql);
/**
* PrepareStatement 方式
* 1.給出sql模板:所有的參數使用?來替代
* 2.調用Connection方法得到PrepareStatement
*/
String sql = "select * from stu WHERE name = ? and password = ? ";
preparedStatement = connection.prepareStatement(sql);
preparedStatement.setString(1,name);
preparedStatement.setString(2,password);
resultSet = preparedStatement.executeQuery();
return resultSet.next();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if(resultSet!=null){
resultSet.close();
}
if(preparedStatement!=null){
preparedStatement.close();
}
if(connection!=null){
connection.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
return false;
}
@Test
public void fun1(){
String userName= "張三";
String password="111111";
String userName2= "錯名' or 'a'='a";
String password2="錯密碼' or 'a'='a";
//正常輸入
System.out.println(login2(userName,password));
//sql注入越過正常邏輯判斷
System.out.println(login2(userName2,password2));
}
fun1()方法login替換爲login2輸出結果:
二預處理原理
·前提:連接點數據庫必須支持預處理,基本數據庫都支持
·每個preparedStatement都與一個sql模板綁定在一起,先把sql模板給數據庫,數據庫先進行校驗,在進行編譯,執行時只是把參數傳遞過去
·若第二次執行,不需再次校驗語法,不用再次編譯,直接執行
mysql打開預編譯功能
useServerPrepStmts=true(是否使用預編譯)
cachePrepStmts=true(設置是否對預編譯使用local cache)
prepStmtCacheSize=256(指定了local cache的大小)