preparestatement继承于statement,由此我们可以得到初步结论:preparestatement在statement的基
础上进一步实现了自己特有的一些方法和属性,preparestatement是对statement的扩展和优化。
1.可读性和可维护性
Statement用于执行静态sql语句,在执行时必须指定一个事先准备好的sql语句。执行的sql是通过拼接字符串
的形式来实现的。
PrepareStatement是预编译的sql语句对象,sql语句被预编译并保存在对象中。被封装的sql语句是通过占位
符“?”来定义的。
Statement用法
<span style="font-family:Verdana;"><span style="font-size:14px;">stmt.executeUpdate("insert into tb_name (col1,col2,col2,col4) values ('"+var1+"','"+var2+"',"+var3+",'"+var4+"')");
</span>
</span>
prepareStatement用法
<span style="font-family:Verdana;">perstmt = con.prepareStatement("insert into tb_name (col1,col2,col2,col4) values (?,?,?,?)");
perstmt.setString(1,var1);
perstmt.setString(2,var2);
perstmt.setString(3,var3);
perstmt.setString(4,var4);
perstmt.executeUpdate();
</span>
对比效果很明了,拼接字符串可读性差,不利于后期维护,尤其是维护其他人拼接的字符串就更一个头两个大了。
2.高性能
prepareStatement把sql语句预先“编译”好放在数据库缓冲区,每次只替换定义的变量,只需编译一次。
Statement每次执行都编译。
使用PrepareStatement对象执行sql时,数据库对SQL进行解析和编译然后放到命令缓冲区。当再次执行同一
个PrepareStatement对象即架构完全相同只是变量不同时,在缓冲区可以发现预编译的命令并重用,因此它只会被
解析而无需再次编译。如果多次重复执行相同的SQL命令,使用PreparedStatement对象减少与数据库的通信量,
从而加快执行速度。但是如果SQL语句只执行一次那么没有什么性能优势。
当使用Statement对象时,每次执行一个SQL命令时,都会对它进行解析和编译。当需要执行Statement对象
多次的时候,PreparedStatement对象将会大大降低运行时间,当然也加快了访问数据库的速度。
更多的关于性能的问题,如在不同数据库之间的差异,还需要进一步验证。
3.安全性
假如现在在登录界面,我要通过验证用户名和密码进行登录。那么使用Statement的拼接SQL串应该为:
String sql = " select * from userInfo where name= '"+varname+"' and passwd='"+varpasswd+'" ";
我现在给出如下登录名和密码:
varname=[aaa]
Passwd=[111' or '1'='1]
带入参数后,得到的SQL实例为:
select * from userInfo where name= 'aaa' and passwd='111' or '1'='1'
而'1'='1'是恒成立的,也就意味着我可以进入系统了。
如果更进一步,我输入密码为
Passwd=[111';drop tableuserInfo]
那么得到的SQL为:
select * from userInfo where name= 'aaa' and passwd='111' ; drop table userInfo
SQL执行后用户信息表就被恶意删除了,后果很严重。这种现象被称为SQL注入。而使用PreparedStatement占位
符就可以很好的防止这种现象的发生。因此Statement多在不带变量或变量为已知的情况下才适用。