一、代码的可读性和可维护性
stmt.executeUpdate("insert into tb_name(col1,col2,col3,col4) values (var1,var2,var3,var4)");
prestmt=conn.prepareStatement("insert into tb_name(col1,col2,col3,col4) values(?,?,?,?)");
prestmt.setString(1,var1);
prestmt.setString(2,var2);
prestmt.setString(3,var3);
prestmt.setString(4,var4);
prestmt.executeUpdate();
将参数与sql语句分离
二、高性能、效率高
每一种数据库都会尽最大努力对预编译语句提供最大的性能优化.因为预编译语句可能被重复调用,语句在被DB的编译器编译后的执行代码被放在缓存中,下次调用时只要相同的预编译语句就不需要再次编译,只需将参数直接传入编译过的语句执行代码中(相当于一个函数)就可以执行。并不是说只有一个connection中多次执行的预编译语句比缓存,而是对于整个DB,只要预编译的语句语法和缓存中匹配,那么在任何时候就可以不需要再次编译而可以直接执行,加快了访问速度.而statement的语句中,即使是相同操作,由于每次操作的数据不相同所以使整个语句相匹配的机会极小,几乎不可能.比如:
insert into tb_name(col1,col2) values("11","22");
insert into tb_name(col1,col2) values("11","23");
相同的操作但因为数据内容不一样,所以整个语句本身不能匹配,没有缓存语句的意义.事实上没有数据库会对普通语句编译后的执行代码缓存,所以每执行一次都要对传入的语句编译一次.
不是所有的预编译语句都一定会被缓存,数据库本身会用一种策略,比如使用频度等因素来决定什么时候不再缓存已有的预编译结果,保证有更多的空间存储新的预编译语句.
三、防止sql注入,极大的提高了安全性
3.1、sql执行机制
(与java字符串创建相似)首先在数据库服务器中查找是否执行过相同的sql语句
如果没有,则进行(sql语法分析,编译...过程),时间很长.(如果是字符串拼凑,每次sql不同,导致重新编译)
如果有,直接取出编译结果,在执行,快
3.2、sql注入(两种方式:入侵和破坏)
SQL注入攻击是利用设计上的漏洞,在目标服务器上运行SQL语句进行攻击,动态生成SQL语句时没有对用户输入的数据进行验证是SQL注入攻击得逞的主要原因.
对JDBC而言,SQL注入攻击只对Statement有效,对PreparedStatement是无效的,这是因为PreparedStatement不允许在插入时改变查询的逻辑结构.
绕过验证,但这种手段只对Statement有效,对PreparedStatement无效.
a、不用用户名密码 where pwd="" or ‘1’=‘1’ 由于‘1’=‘1’始终返回ture,所以通过验证
b、把;dorp table tb_name;作为pwd
黑客可以根据字符串拆分来注入
3.3、预编译语句对象:防范sql注入
ps.setInt(1,id);//这里的数据库语句所用到的参数要被设置的,如果你传入了错的值,或不同类型的值,
它在插入到数据库语句中会编译不通过,这也就防止了SQL注入
3.4、什么场合不能用预编译?
3.5、什么时候使用预编译语句?
一般是在需要反复使用一个SQL语句时才使用预编译语句,预编译语句常常放在一个fo r或者while循环里面使用,通过反复设置参数从而多次使用该SQL语句。为了防止SQL注入漏洞,在某些数据操作中也使用预编译语句。
3.6、实现机制不同,注入只对SQL语句的准备(编译)过程有破坏作用,而PreparedStatement已经准备好了,执行阶段只是把输入串作为数据处理,不再需要对SQL语句进行解析,准备,因此也就避免了SQL注入问题.