编程语言 php java

Statement和PreparedStatement的区别

java HTML我帮您 1年前  0次浏览
PreparedStatement 接口继承了Statement,因此PreparedStatement比Statement功能更强大,有人主张,在JDBC应用中,应该始终以PreparedStatement代替Statement。也就是说,在任何时候都不要使用Statement。
大部分关系型数据库通过JDBC进行SQL查询,分以下4步。
1.转换SQL。
2.编译SQL。
3.优化数据查询路径。
4.执行最优化的查寻,并返回数据。
Statement对于每一个SQL查询总是处理这4步。而PreparedStatement对象已经预先执行了步骤1-3,这样的话,当PreparedStatement只需要做查询动作,因此比Statement会快很多。并且PreparedStatement能够防止sql注入攻击,可以使用?作为参数,然后调用方法setXxx()来为参数赋值


一、在编写代码过程:

Statement:

stmt.executeUpdate("insert into tb_name (col1,col2,col2,col4) values ('"+var1+"','"+var2+"',"+var3+",'"+var4+"')");

PreparedStatement:

pstmt = con.prepareStatement("insert into tb_name(col1,col2,col2,col4) values (?,?,?,?)"); pstmt.setString(1,var1); pstmt.setString(2,var2); pstmt.setString(3,var3); pstmt.setString(4,var4); pstmt.executeUpdate();

可以看出来statement的代码写起来比较少但是给人的感觉就是乱,而且还容易出错;但是preparedStatement的代码虽然长一点,但是直接一个.就可以敲出来,给人的感觉是简单而且不容易出错。

对于一些非字符串的值,比如Date, Time, Timestamp, BigDecimal, InputStream (Blob) 等值,也可以在循环内调用setObject方法来设置值。如下:

public static void setValues(PreparedStatement preparedStatement, Object... values) throws SQLException {
for (int i = 0; i < values.length; i++) {
preparedStatement.setObject(i + 1, values);
}
}



二、在性能方面:

如果是大型的软件,需要保存在数据库中的数据量是非常大的,那么就要涉及到性能问题,无论是oracle还是SQL server都是这样的,每一种数据库都会近最大的努力对预编译语句提供最大的性能优化,因为有些编译语句有可能被重复调用。所以就有把被数据库编译后的执行代码缓存起来,当下次调用只要是相同的预编译语句就不需要编译。只要将参数直接传入编译过的语句执行代码中(相当于一个涵数)就会得到执行.这并不是说只有一个Connection中多次执行的预编译语句被缓存,而是对于整个DB中,只要预编译的语句语法和缓存中匹配.那么在任何时候就可以不需要再次编译而可以直接执行.而statement的语句中,即使是相同一操作,而由于每次操作的数据不同所以使整个语句相匹配的机会极小,几乎不太可能匹配.比如:
insert into tb_name (col1,col2) values ('11','22');
insert into tb_name (col1,col2) values ('11','23');
即使是相同操作但因为数据内容不一样,所以整个个语句本身不能匹配,没有缓存语句的意义.事实是没有数据库会对普通语句编译后的执行代码缓存.
当然并不是所以预编译语句都一定会被缓存,数据库本身会用一种策略,比如使用频度等因素来决定什么时候不再缓存已有的预编译结果.以保存有更多的空间存储新的预编译语句.这样能保持一种内存空间的平衡,不至于因为有过多的缓存而崩溃。

三、安全性

安全性是软件中最重要的一个问题,如果你的软件存在安全性问题那么你的软件也就无人问津了。而preparedStatement和statement就存在这样的问题。

在视频中讲解了一下sql注入的问题。

String sql = "select * from tb_name where name= '"+varname+"' and passwd='"+varpasswd+"'";
如果我们把<' or '1' = '1>作为varpasswd传入进来.用户名hzy,看看会成为什么?
select * from tb_name = 'hzy' and passwd = '' or '1' = '1';
因为'1'='1'肯定成立,所以可以任何通过验证.更有甚者:
把drop table tb_name;>作为varpasswd传入进来,则:
select * from tb_name = '随意' and passwd = '';drop table tb_name;有些数据库是不会让你成功的,但也有很多数据库就可以使这些语句得到执行.
而如果你使用预编译语句.你传入的任何内容就不会和原来的语句发生任何匹配的关系.只要全使用预编译语句,你就用不着对传入的数据做任何过虑.而如果使用普通的statement,有可能要对drop,;等做费尽心机的判断和过虑.

PreparedStatement继承于Statement,通常的JDBC实现中PreparedStatement最终还是通过Statement的相关方法来执行SQL的(可以做少量优化),其最主要的优势在于,可以减少SQL的编译错误(在JDBC中就可以捕获部分异常而不是由数据库服务器执行时返回错误代码)、增加SQL安全性(减少SQL注入的机会)

把PreparedStatement说的如此之好,并不是说statement就没有存在的意义了,对于不重复使用和可以控制输入值的情况下statement在性能上还是比较好的。每个东西都有它存在的必然道理,对与解决的问题的办法没有绝对的好也没有绝对的不好,合适就好。

发表评论