Java数据库预处理

Java数据库预处理教程

前面文章中我们了解到真正执行 sql 语句的是 Statement 对象。它执行相应的方法就能够操作数据库。这边给他传递的 sql 语句都是瓶装好的语句。它其实是不安全的,如果别有用心的人可以在 sql 语句上面动点手脚,就会导致系统有问题。

预处理就和现实生活中的占座的道理是一样的,如果你和嗨客礼拜天约定一起去图书馆看书,你先到了图书管,嗨客临时有事要半个小时没来,这个时候,你就会帮嗨客占一个位置,不管他有没有到,这个位置就是它的了。

Java 语言里面就定义了一个 PreparedStatement 接口来处理预处理。它是 Statement 的子接口,所以调用方式和 Statement 差不多。

Java PreparedStatement

说明

PreparedStatement 对象已经预编译过,它的执行速度会比 Statement 对象快。在 PreparedStatement 对象中它对具体的内容用 “?” 来占位,然后设置内容的时候,按照 “?” 的内容来对数据进行赋值。

常用方法

方法名 描述
int executeUpdate() throws SQLException 执行设置的预处理 SQL 语句
ResultSet executeQuery() throws SQLException; 执行数据库查询操作
void setInt(int parameterIndex, int x) throws SQLException; 在指定的索引的位置赋值,赋值类型是 int 类型
void setFloat(int parameterIndex, float x) throws SQLException; 在指定的索引的位置赋值,赋值类型是 float 类型
void setString(int parameterIndex, String x) throws SQLException; 在指定的索引位置赋值,赋值类型是 String 类型。

其实 基本的数据类型 这边都可以设置,设置方式和上面的表格类型,但是有一个特殊的类型是 Date 类型。我们平时代码里面用的是 java.util.Date 类型,但是 mysql 这边操作的时候需要用 java.sql.Date 类型。

案例

我们使用 sql 预处理的方式进行插入数据和查询数据,查询我们可以试着模糊查询。

import java.sql.*; public class MysqlTest { public static final String DBDRIVER = "com.mysql.jdbc.Driver"; public static final String DBURL = "jdbc:mysql://localhost:3306/haicoder"; public static final String DBUSER = "root"; public static final String PASSWORD = "123456"; public static void main(String[] args) throws Exception { System.out.println("嗨客网(www.haicoder.net)"); Connection connection = null; //加载驱动 Class.forName(DBDRIVER); //创建连接 connection = DriverManager.getConnection(DBURL, DBUSER, PASSWORD); String sql = "INSERT INTO person (username,age) values (?,?)"; //创建 statement 对象 PreparedStatement statement = connection.prepareStatement(sql); statement.setString(1, "嗨客网"); statement.setInt(2, 100); //执行sql statement.executeUpdate(); statement.setString(1, "IT 社区"); statement.setInt(2, 100); statement.executeUpdate(); String querySql = "select username,age from person where username like ?"; PreparedStatement queryStatement = connection.prepareStatement(querySql); queryStatement.setString(1, "%嗨客%"); ResultSet resultSet = queryStatement.executeQuery(); while (resultSet.next()) { String name = resultSet.getString("username"); Integer age = resultSet.getInt("age"); System.out.println("name in db is :" + name + " age in db is :" + age); } //关闭操作 statement.close(); queryStatement.close(); //关闭数据库连接 connection.close(); System.out.println("结束"); } }

运行结果如下:

13 preparement.png

我们插入了两条记录,然后用模糊搜索,查询出名字里面包含 嗨客 的数据。

Java SQL注入

sql 注入的意思是通过传递一些参数,让我们的 sql 执行改变意志。比如我们模糊查询 person 表,按照名字来模糊查询数据。我们使用预处理方式查询和直接查询。

import java.sql.*; public class MysqlTest { public static final String DBDRIVER = "com.mysql.jdbc.Driver"; public static final String DBURL = "jdbc:mysql://localhost:8080/haicoder"; public static final String DBUSER = "root"; public static final String PASSWORD = "123456"; public static void main(String[] args) throws Exception { System.out.println("嗨客网(www.haicoder.net)"); Connection connection = null; //加载驱动 Class.forName(DBDRIVER); System.out.println("=======sql 预处理 开始======="); //创建连接 connection = DriverManager.getConnection(DBURL, DBUSER, PASSWORD); String querySql = "select username,age from person where username like ?"; PreparedStatement queryStatement = connection.prepareStatement(querySql); queryStatement.setString(1, "'%嗨客%' OR 1=1"); ResultSet resultSet = queryStatement.executeQuery(); while (resultSet.next()) { String name = resultSet.getString("username"); Integer age = resultSet.getInt("age"); System.out.println("name in db is :" + name + " age in db is :" + age); } System.out.println("=======sql 预处理 结束======="); System.out.println("=======sql 注入 开始======="); //创建 statement 对象 Statement statement = connection.createStatement(); String statementSql = "select * from person where username like '%嗨客%' OR 1=1"; //执行sql ResultSet statementResultSet = statement.executeQuery(statementSql); while (statementResultSet.next()) { String name = statementResultSet.getString("username"); Integer age = statementResultSet.getInt("age"); System.out.println("name in db is :" + name + " age in db is :" + age); } System.out.println("=======sql 注入 结束======="); //关闭操作 queryStatement.close(); statement.close(); //关闭数据库连接 connection.close(); System.out.println("结束"); } }

运行结果如下

14 sql 注入.png

我们可以看到,使用 Statement 来查询 sql 的时候,在 条件里面 加了一个 or 1=1 ,sql 语句就变了,所以它将数据库里面的所有语句都查询了出来,而使用预处理的时候,它认为是将 username 是 ‘%嗨客%’ OR 1=1 查询出来,从而没有记录。

Java数据库预处理总结

在真实的生产环境中,我们对数据库操作使用 PreparedStatement 比较多,它是安全的,防止 sql 依赖注入的。而且 PreparedStatement 效率比 Statement 效率高。