大家都知道,在使用JDBC连接数据库时,需要创建执行SQL语句的Statement。实际上有三种 Statement 对象,它们都作为在给定连接上执行 SQL 语句的包容器:Statement、PreparedStatement(它从 Statement 继承而来)和 CallableStatement(它从 PreparedStatement 继承而来)。
诚然,它们都专用于发送特定类型的 SQL 语句,可是它们究竟有何区别呢?我们在代码实现时究竟该选择哪种呢?下面我们就来详细的分析一下Statement和PreparedStatement的区别。
注:CallableStatement 对象是用于执行对数据库已存在的存储过程,区别性很强,再次不再参与比较。
下面先贴上分别使用Statement和PreparedStatement的代码,方便读者您对我下面说阐述的三点区别理解更深刻。
//使用Statement对象执行Sql更新语句
stmt.executeUpdate("insert into tb_name (col1,col2,col3,col4) values ('"+var1+"','"+var2+"',"+var3+",'"+var4+"')");
//使用PreparedStatement对象执行Sql更新语句
perstmt = con.prepareStatement("insert into tb_name (col1,col2,col3,col4) values (?,?,?,?)");
perstmt.setString(1,var1);
perstmt.setString(2,var2);
perstmt.setString(3,var3);
perstmt.setString(4,var4);
perstmt.executeUpdate();
区别一:预编译
数据库都会尽最大努力对预编译语句提供最大的性能优化。因为预编译语句有可能被重复调用。所以语句在被DB的编译器编译后的执行代码会被缓存下来,那么下次调用时只要是相同的预编译语句就不需要编译,只要将参数直接传入编译过的语句执行代码中(相当于一个涵数)就会得到执行。
statement的语句中,即使是相同一操作,而由于每次操作的数据不同所以使整个语句相匹配的机会极小,几乎不太可能匹配.比如:
insert into tb_name (col1,col2,col3,col4) values ('11','22','33','44');
insert into tb_name (col1,col2,col3,col4) values ('12','23','34','45');
即使是相同操作但因为数据内容不一样,所以整个语句本身不能匹配,没有缓存语句的意义。事实是没有数据库会对普通语句编译后的执行代码缓存。
而PreparedStatement的第一次执行消耗是很高的,它的性能体现在后面的重复执行。相比于Statement直接编译 SQL 语句,然后扔给数据库执行,PreparedStatement则是PreparedStatement先将 SQL 语句预编译一遍,再填充参数,这样效率会高一些。JDK 文档说:SQL 语句被预编译并且存储在 PreparedStatement 对象中,其后可以使用该对象高效地多次执行该语句。
区别二:可读和可维护性
就上面两段代码来看,好像使用PreparedStatement对象代码反而比Statement对象多了?确实是的。那么它究竟是如何体现出它的可读性和可维护性的呢?
对于初学者来说,显然,使用PreparedStatement对象的代码更清晰了然,不用仔细分析拼接SQL字符串这么麻烦的事情了。而对于后期需要对你代码进行维护的人员,一旦数据库表字段发生变化,他只需要使用PreparedStatement对象的setString来增加或者改变参数即可,彻底告别了复杂的拼接SQL字符串。
区别三:安全性
这里的安全性,就是我们常说的SQL注入了。到底是什么SQL注入呢?为什么使用PreparedStatement可以避免SQL注入呢?上例子吧。
假如SQL语句为:String sql = "select * from tb_name where name= '"+varname+"' and passwd='"+varpasswd+"'";
如果用户随意输入name,并且把[' or '1' = '1]作为varpasswd传入进来,看看我们的SQL会成为什么?
select * from tb_name = '随意' and passwd = '' or '1' = '1';
熟悉SQL语句执行的读者肯定可以看出,这条语句是永远成立,可以说是永远正确的。就这样,非法用户就直接可以登录我们的系统了。这个过程,就是我们常说的SQL注入。
所以,显然使用拼接字符串的方式是很不安全的。而PreparedStatement对象则采用使用?号的方式传递参数,进而避免了SQL注入。
从这三方面详细分析了Statement和PreparedStatement两者的区别,你懂了吗?