JDBC基础二(PreparedStatemrnt与Statement)

Statement的缺陷

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
package com.zss.jdbc;

import java.sql.*;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
/**
* @author 张硕硕
*/
public class test {
public static void main(String [] args){
Map<String,String> haha= test.initUi();
System.out.println(test.login(haha)?"登陆成功":"登陆失败");
}
private static Map<String ,String > initUi(){
Scanner scanner=new Scanner(System.in);
System.out.println("请输入您的用户名");
String userName=scanner.nextLine();
System.out.println("请输入您的登录密码");
String password=scanner.nextLine();
Map<String,String> userInformation=new HashMap<>();
userInformation.put("username",userName);
userInformation.put("password",password);
return userInformation;
}
private static boolean login(Map<String,String> userInformation){
boolean loginY=false;
Connection connection=null;
Statement statement=null;
ResultSet resultset=null;
try{
Class.forName("com.mysql.cj.jdbc.Driver");
connection= DriverManager.getConnection("jdbc:mysql://localhost:3306/userinformation","root","200101");
statement=connection.createStatement();
String sql="select * from user where 用户名= '"+userInformation.get("username")+"'and 密码= '"+userInformation.get("password")+"'";
resultset=statement.executeQuery(sql);
if (resultset.next()){loginY=true;}
}
catch (Exception e){e.printStackTrace();}

finally {
if (resultset!=null){try{resultset.close();}catch (Exception e){e.printStackTrace();}}
if (statement!=null){try{statement.close();}catch (Exception e){e.printStackTrace();}}
if (connection!=null){try{connection.close();}catch(Exception e){e.printStackTrace();}}

}
return loginY;
}

}

image-20220322161854943

image-20220322162721137

  • 大家按照如图中信息去输入,可以惊奇的发现,账号密码完全不对,可是怎么就可以登录???

是因为在编译过程中,数据将密码传输给mysql语句,导致mysql语句句意发生改变,大家仔细查看在调试过程中,sql语句句意发生了改变,导致这个验证根本无效,可以直接通过这个登录。

image-20220322162842524

PreparedStatement

预编译是将语句首先传入,但是将位置用?留出,等到后面在进行传入。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
package com.zss.jdbc;

import java.sql.*;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
/**
* @author 张硕硕
*/
public class test {
public static void main(String [] args){
Map<String,String> haha= test.initUi();
System.out.println(test.login(haha)?"登陆成功":"登陆失败");
}
private static Map<String ,String > initUi(){
Scanner scanner=new Scanner(System.in);
System.out.println("请输入您的用户名");
String userName=scanner.nextLine();
System.out.println("请输入您的登录密码");
String password=scanner.nextLine();
Map<String,String> userInformation=new HashMap<>();
userInformation.put("username",userName);
userInformation.put("password",password);
return userInformation;
}
private static boolean login(Map<String,String> userInformation){
boolean loginY=false;
Connection connection=null;
PreparedStatement preparedStatement=null;
ResultSet resultset=null;
try{
Class.forName("com.mysql.cj.jdbc.Driver");
connection= DriverManager.getConnection("jdbc:mysql://localhost:3306/userinformation","root","200101");
String sql="select * from user where 用户名= ? and 密码= ? ";
preparedStatement=connection.prepareStatement(sql);
preparedStatement.setString(1,userInformation.get("username"));
preparedStatement.setString(2,userInformation.get("password"));
resultset= preparedStatement.executeQuery();
if (resultset.next()){loginY=true;}
}
catch (Exception e){e.printStackTrace();}

finally {
if (resultset!=null){try{resultset.close();}catch (Exception e){e.printStackTrace();}}
if (preparedStatement!=null){try{preparedStatement.close();}catch (Exception e){e.printStackTrace();}}
if (connection!=null){try{connection.close();}catch(Exception e){e.printStackTrace();}}

}
return loginY;
}

}

image-20220322163801146

说明

  1. 在大部分情况下,PreparedStatementStatement更加广泛,而且更加安全。
  2. PreparedStatementStatement运行更加快速,在mysql中,如果连续两条语句一模一样,这样编译器不会对语句进行重新编译,而是直接将赋值进行操作。
  3. 在部分特殊情况下,还是需要使用Statement,因为部分企业需求需要进行注入。(比如我们常见的商品按照价格排序界面,需要有order by desc/asc时,利用 PreparedStatement传输desc值或者asc值时,会为这两个值带上引号,语句无法识别,此时使用Statement更加方便。