参考资料:http://how2j.cn?p=28607、https://blog.csdn.net/qqhjqs/article/details/47262673
百度百科简介:java.sql包中的PreparedStatement 接口继承了Statement,并与之在两方面有所不同:有人主张,在JDBC应用中,如果你已经是稍有水平开发者,你就应该始终以PreparedStatement代替Statement.也就是说,在任何时候都不要使用Statement。
一、使用方法
import java.sql.*;
public class PreparedStmt {
public static void main(String[] args) {
String driverName = "com.microsoft.sqlserver.jdbc.SQLServerDriver";
String dbUrl = "jdbc:sqlserver://localhost:1433;DatabaseName=SC";
String userName = "test";
String userPwd = "test";
Connection conn = null;
PreparedStatement pStmt = null;
try {
Class.forName(driverName);
conn = DriverManager.getConnection(dbUrl, userName, userPwd);
String sql = "insert into course values(?,?,?,null)";
pStmt = conn.prepareStatement(sql);//注意是prepareStatement()方法
} catch (SQLException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
try {
//设置参数的值
pStmt.setString(1, "1009");
pStmt.setString(2, "JDBC教程");
pStmt.setDouble(3, 3.5);
pStmt.execute();
} catch (SQLException e) {
e.printStackTrace();
}
try {
if(pStmt != null) pStmt.close();
if(conn != null) conn.close();
} catch(SQLException e) {
e.printStackTrace();
}
}
}
注意:1.设置参数值的地方是JAVA里唯二的基1(从一开始)的地方,另一个是查询语句中的ResultSet也是基1的。
2.在执行 PreparedStatement 对象之前,必须设置每个 ? 参数的值。这可通过调用 setXxx 方法来完成,其中 Xxx须是与该参数相应的类型。
二、与Statement相比的优点
1.Statement 需要进行字符串拼接,可读性和维护性比较差
String sql = "insert into hero values(null,"+"'提莫'"+","+313.0f+","+50+")"
PreparedStatement 使用参数设置,可读性好,不易犯错
String sql = "insert into hero values(null,?,?,?)";
2.PreparedStatement尽最大可能提高性能.
insertintotb_name(col1,col2)values('11','22');
insertintotb_name(col1,col2)values('11','23');
即使是相同操作但因为数据内容不一样,所以整个个语句本身不能匹配,没有缓存语句的意义.事实是没有数据库会对普通语句编译后的执行代码缓存.
3.防止SQL注入式攻,提高安全性
假设name和passwd是用户传来的数据,有下方语句:String sql="select * from tb_name where name ='" +name +"'and passwd='"+passwd+"'";
如果我们把['or'1'='1]作为passwd传入进来,用户名随意,则执行的SQL语句会是:
select * from tb_name ='任意字符' and passwd='' or '1'='1';
因为'1'='1'肯定成立,所以可以任意通过验证.更有甚者把[';drop table tb_name;]作为passwd传入进来,则SQL语句会被改写成:
select * from tb_name ='随意'and passwd='';drop table tb_name;
而如果你使用预编译语句,你传入的任何内容就不会和原来的语句发生任何匹配的关系。只要全使用预编译语句,你就用不着对传入的数据做任何过虑。而如果使用普通的statement,有可能要对drop等做费尽心机的判断和过滤。
select * from t_user where password='ddd\' or \'1\'=\'1';
它会把恶意的注入语句预处理为参数。
注意:和Statement不不同的是,使用PreparedStatement时,是无法直接使用System.out.println(SQL)输出当前执行的SQL语句的,此时输出的结果会是: