JDBC-PreparedStatement对象

JDBC-PreparedStatement对象介绍

说明:使用上面的知识已经完全可以使用Java来操作oracle数据库的内容,接下来讲的这部分内容是拓展内容,若读者时间宝贵,可直接跳往下一节。

PreparedStatement对象

本篇博客主要说了与Statement相对应的PreparedStatement,它是Statement类的一个子类,但是可以避免sql注入带来的风险。你问我什么是sql注入?看下面代码的文档说明那部分就清楚啦,不相信的可以自己试试。

在放代码之前,我们先来看一下上面两者的差别。

StatementPreparedStatement两者的差别很小,它们使用JDBC的步骤也基本相同,唯一不同的是sql语句的书写形式不同,PreparedStatement的sql语句空缺部分使用英文状态下的?占位符进行填充,而Statement在前面大家也都看到过了,就完全是字符串的拼接。另外,PreparedStatement在创建sql命令对象之前就应该编写完sql命令,并将其放入命令对象,而Statement不做要求。

这两者各有各的优点,也有各自的不足,不存在哪个好那个不好的问题,要根据实际问题进行合理运用。因为Statement虽然会出现sql注入的风险,但是我们也会对重要的数据进行加密,所以即使泄露,问题也不大。PreparedStatement虽然可以避免sql注入,提升sql语句的执行效率(PraparedStatement有预编译过程),但是由于它的格式是定死的了,就不能进行字符串的拼接,会丧失一些灵活性。

具体请看代码吧,我会把代码的结构图发在下面,大家可以自己创建一个项目复制过去进行体会,大家一定要看测试代码中的文档注释。

LogonDao.java

1
2
3
4
5
6
7
8
9
10
11
12
package com.baidu.Dao;
import com.baidu.pojo.Logon;

/*
* 增删改操作,为了大家更方便体会Statement与PreparedStatement的区别,就不再演示了。
* 基本步骤基本相同
*/
public interface LogonDao {
//登录认证
public Logon getLogon(String name,String pass);

}

LogonDaoImpl.java

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
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
package com.baidu.DaoImpl;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import com.baidu.Dao.LogonDao;
import com.baidu.pojo.Logon;

/**
* 在PreparedStatement中sql字符串要先于sql命令对象来定义。
* 给占位符赋值: 占位符从左到右角标从1开始
* @author x1aolin
*
*/
public class LogonDaoImpl implements LogonDao {
//查询登录信息
public Logon getLogon(String name, String pass) {
Logon lo = new Logon();
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
//加载驱动
Class.forName("oracle.jdbc.driver.OracleDriver");
String url = "jdbc:oracle:thin:@localhost:1521:XE";
//创建数据库连接对象
conn = DriverManager.getConnection(url, "hh", "123456");
//创建sql语句 会更改写法:?为占位符
String sql = "select * from logon where sname = ? and spassword = ?";
//创建sql命令对象
ps = conn.prepareStatement(sql);
//给占位符赋值(占位符从左到右角标从1开始)
ps.setString(1, name);
ps.setString(2, pass);
//执行sql命令 不要传值 传值会传上面没赋值的sql语句
rs = ps.executeQuery();
while(rs.next()){
lo.setName(rs.getString("sname"));
lo.setPassword(rs.getString("spassword"));
return lo;
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
try {
ps.close();
} catch (SQLException e) {
e.printStackTrace();
}
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
return null;
}
}

Logon.java

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
package com.baidu.pojo;

public class Logon {
private String name;
private String password;
public Logon() {
super();
}
public Logon(String name, String password) {
super();
this.name = name;
this.password = password;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}

Test.java

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
53
54
55
package com.baidu.test;

/**
* 问题:
* 使用Statement对象进行数据库操作的时候可能会产生sql注入的风险。
* 比如说本例中的密码位置若输入xxxx'or'1'='1,则无论用户名是什么,一定会显示登陆成功,
* 完整的sql语句为:
* select * from logon where sname = 'xxxx' and spassword = xxxx'or'1'='1'
* 它并不会把xxxx'or'1'='1当作密码那个属性来执行,而是将其拼成一整个sql命令后再进行执行,
* 大家也清楚,在sql中and优先级是要高的,当执行时就会打印出整个表。
* 解决:
* 使用preparedStatement
* 使用:
* 声明集合或实体类对象(可选-查询)
* 加载驱动
* 获取连接对象
* 设置手动数据提交(可选-增删改)
* 创建sql命令
* 获取sql命令对象
* 给占位符赋值
* 执行sql命令
* 遍历结果(可选-查询)
* 提交数据(可选-增删改)
* 回滚数据(可选-增删改)
* 关闭资源
* 返回结果
* 特点:
* 防止sql注入
* 提升sql语句的执行效率(PraparedStatement有预编译过程)
* 当我们重复的执行某条命令的时候,就可以看出 编译和预编译的区别,
* 同一条命令执行n次,编译需要n次,而预编译仅仅需要1次即可。
*/
import java.util.Scanner;
import com.baidu.Dao.LogonDao;
import com.baidu.DaoImpl.LogonDaoImpl;
import com.baidu.pojo.Logon;

public class Test {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("用户名:");
String name = sc.next();
System.out.println("密码");
String ps = sc.next();
System.out.println(name+"---"+ps);

LogonDao l = new LogonDaoImpl();
Logon lo = l.getLogon(name, ps);

if(lo!=null)
System.out.println("登录成功");
else
System.out.println("登陆失败");
}
}

强烈建议大家复制到自己的IDE中进行调试参考。

您的每一份支持将鼓励我继续创作!
-------------本文结束感谢您的阅读-------------