JDBC之PreparedStatement 详解

简介

PreparedStatement 是一个特殊的Statement对象,如果我们只是来查询或者更新数据的话,最好用PreparedStatement代替Statement,因为它有以下有点:

  1. 简化Statement中的操作
  2. 提高执行语句的性能
  3. 可读性和可维护性更好
  4. 安全性更好。
  5. 使用PreparedStatement能够预防SQL注入攻击,所谓SQL注入,指的是通过把SQL命令插入到Web表单提交或者输入域名或者页面请求的查询字符串,最终达到欺骗服务器,达到执行恶意SQL命令的目的。注入只对SQL语句的编译过程有破坏作用,而执行阶段只是把输入串作为数据处理,不再需要对SQL语句进行解析,因此也就避免了类似select * from user where name=’aa’ and password=’bb’ or 1=1的sql注入问题的发生。

Statement 和 PreparedStatement之间的关系和区别.

  • 关系:PreparedStatement继承自Statement,都是接口
  • 区别:PreparedStatement可以使用占位符,是预编译的,批处理比Statement效率高

入门使用

创建PreparedStatement

创建一个PreparedStatement PreparedStatement对象的创建也同样离不开 DriverManger.getConnect()对象,因为它也是建立在连接到数据库之上的操作。

1
2
3
4
5
6
7
8
/** 1. init PreparedStatement*/
Class.forName("com.mysql.jdbc.Driver");
String url = "jdbc:mysql://localhost:3306/db_test?useSSL=false";
String username = "root";
String password = "root";
Connection connection = DriverManager.getConnection(url, username, password);
String sql = "update user set username=? where id = ?";
PreparedStatement preparedStatement = connection.prepareStatement(sql);

设置入参

往PreparedStatement里写入参数

看上面那个sql 字符串,中间有几个?,它在这里有点占位符的意思,然后我们可以通过PreparedStatement的setString(),等方法来给占位符进行赋值,使得sql语句变得灵活。

1
2
3
/** 2. prepare param*/
preparedStatement.setString(1, "feifz");
preparedStatement.setInt(2, 2);

参数中的第一个参数分别是1和2,它代表的是第几个问号的位置。如果sql语句中只有一个问号,那就不用声明这个参数。

执行更新

1
2
3
/** 3. execute update*/
int result = preparedStatement.executeUpdate();
System.out.printf("更新记录数:"+result+"\n");

结果:

1
更新记录数:1

执行查询

如果是执行查询数据库的话,也像Statement对象执行excuteQuery()一样返回一个ResultSet结果集。

1
2
3
4
5
6
7
8
9
/** 4. execute select*/
String sql2 = "select * from user";
ResultSet resultSet = preparedStatement.executeQuery(sql2);
while (resultSet.next()) {
int id = resultSet.getInt("id");
String username = resultSet.getString("username");
String dept = resultSet.getString("dept");
System.out.println("id:"+id +"username->"+ username + ",dept-> " + dept );
}

执行结果:

1
2
3
4
5
id:1username->Fant.J,dept-> 测试部
id:2username->feifz,dept-> 研发部
id:3username->xixi,dept-> 产品部
id:4username->hah,dept-> 集成部
id:5username->zeze,dept-> 研发部

完整代码

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
package com.github.feifuzeng.middleware.mybatis.jdbc;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;

/**
* @author feifz
* @version 1.0.0
* @Description PreparedStatement简单demo
* @createTime 2019年08月29日 20:21:00
*/
public class PrepareStatementSimpleDemo {

public static void main(String[] args) throws Exception {

/** 1. init PreparedStatement*/
Class.forName("com.mysql.jdbc.Driver");
String url = "jdbc:mysql://localhost:3306/db_test?useSSL=false";
String user = "root";
String password = "root";
Connection connection = DriverManager.getConnection(url, user, password);
String sql = "update user set username=? where id = ?";
PreparedStatement preparedStatement = connection.prepareStatement(sql);

/** 2. prepare param*/
preparedStatement.setString(1, "feifz");
preparedStatement.setInt(2, 2);

/** 3. execute update*/
int result = preparedStatement.executeUpdate();
System.out.printf("更新记录数:"+result+"\n");

/** 4. execute select*/

String sql2 = "select * from user";
ResultSet resultSet = preparedStatement.executeQuery(sql2);
while (resultSet.next()) {
int id = resultSet.getInt("id");
String username = resultSet.getString("username");
String dept = resultSet.getString("dept");
System.out.println("id:"+id +"username->"+ username + ",dept-> " + dept );
}


}
}

参考

  1. https://juejin.im/post/5abb78c8f265da23994e9643