1、在SQL中包含特殊字符串或SQL的关键字(如:’or 1 or’)时,Statement将出现不可预料的结果(出现异常或查询的结果不正确),可用PreparedStatement来解决。
2、PreparedStatement(从Statement扩展而来)相对Statement的优点:
①没有SQL注入的问题;
②Statement会使数据库频繁编译SQL,可能造成数据库缓冲区溢出;
2、PreparedStatement(从Statement扩展而来)相对Statement的优点:
①没有SQL注入的问题;
②Statement会使数据库频繁编译SQL,可能造成数据库缓冲区溢出;
③数据库和驱动可以对PreparedStatement进行优化(只有在相关联的数据库连接没有关闭的下有效);
④PreparedStatement效率比Statement效率高,但是在第一次执行的时候,PreparedStatement需要进行预编译处理,会比Statement效率低。
3、测试SQL注入SQLInject.java中的代码
package cn.itcast.jdbc;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import org.junit.Test;
/**
* 演示SQL注入,Statement和PreparedStatement的区别
*/
public class SQLInject {
/**
* 这种方式会存在SQL注入的问题
* @throws SQLException
*/
@Test
public void testStatement() throws SQLException {
//readByStatement("lisi");
//这里表示值是'或者1或者',即单引号
readByStatement("' or 1 or '");
}
/**
* 使用这种方式经过测试查询不出结果
* @throws SQLException
*/
@Test
public void testPreparedStatement() throws SQLException {
readByPreparedStatement("' or 1 or '");
}
/**
* 使用PreparedStatement执行查询
* @param name
* @throws SQLException
*/
static void readByPreparedStatement(String name) throws SQLException {
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try{
//JdbcUtils参见上一篇博客
conn = JdbcUtils.getConnection();
String sql = "select id, name, money, birthday from user where name=?";
//会对SQL语句进行预编译
ps = conn.prepareStatement(sql);
//注意下标从1开始
ps.setString(1, name);
//执行语句
rs = ps.executeQuery();
//处理结果
while(rs.next()) {
System.out.println(rs.getInt("id") + "\t"
+ rs.getString("name") + "\t"
+ rs.getDate("birthday")
+ "\t" + rs.getFloat("money"));
}
}finally{
JdbcUtils.free(rs, ps, conn);
}
}
/**
* 通过Statement查询数据,存在SQL注入的问题
* @param name
* @throws SQLException
*/
static void readByStatement(String name) throws SQLException {
Connection conn = null;
Statement st = null;
ResultSet rs = null;
try{
conn = JdbcUtils.getConnection();
conn.getAutoCommit();
st = conn.createStatement();
String sql = "select id, name, money, birthday from user where name='"
+ name + "'";
System.out.println("SQL:" + sql);
rs = st.executeQuery(sql);
while(rs.next()) {
System.out.println(rs.getInt("id") + "\t"
+ rs.getString("name") + "\t" + rs.getDate("birthday")
+ "\t" + rs.getFloat("money"));
}
} finally {
JdbcUtils.free(rs, st, conn);
}
}
}
测试结果:
运行testStatement方法,得到如下结果(数据库中的结果全部被查询来):
SQL:selectid, name, money, birthday from userwhere name='' or 1 or ''
1 zhangsan 2017-06-30 110.0
2 lisi 2017-06-06 210.0
3 wangwu 2017-05-30 310.0
4 name1 1987-01-01 410.0
运行readByPreparedStatement方法,打印不出任何结果。