什么是预编译语句

来源:互联网 发布:s71200编程软件 编辑:程序博客网 时间:2024/06/04 18:38

SQL预编译

ibatis中如何解决sql注入问题,资料参考

-------------引文内容------------

来源: 我爱测试 作者:阚宝丽  发表日期: 2011-4-18 16:09:11 阅读次数: 702 

在java连接数据库操作时,我们经常看见如下SQL语句,它通过字符串连接的方式,将输入参数拼成一段SQL语句:
   代码段一:
   String sqlSt = “sel ect* from table1 where name=”+tb_name+” and passwo rd=”+tb_pwo rd;
   Statement st = con.createStatement();//其中con是Connection对象。
   ResultSet rsSt = st.exe cuteQuery(sqlSt);
 
    还有以下的一种写法:
   代码段二:
   String sqlPst = “sel ect* from table1 where name = ? and passwo rd = ?”;
   PrepareStatement pst = con.createPreparementStatement();//其中con是Connection对象。
   ResultSet rsPst = pst.exe cuteQuery(sqlPst);
 
   以上两段代码都是执行查询语句,不同的是代码段一创建的是Statement对象,而代码段二创建的是PrepareStatement对象,那两种有什么区别吗?
   当然有区别!
   对于代码段一,如果我们把[' o r '1' = '1]作为tb_pwo rd传入进来.用户名随意,看看会成为什么?
   sel ect* from table1 name = '随意' and passwo rd = '' o r '1' = '1';因为'1'='1'肯定成立,所以可以任何通过验证.
   这在安全性方面是一个致命的漏洞,这就是sql注入,而代码段二则不会,因为它采用了预编译语句,sql注入只对sql语句的准备(编译)过程有破坏作用,而PreparedStatement已经准备(编译)好了,执行阶段只是把输入串作为数据处理,而不再对sql语句进行解析、准备(编译),因此也就避免了sql注入问题。
   下面我们就来详细看一下有关预编译的一些知识。
   1、什么是预编译语句
   预编译语句PreparedStatement 是java.sql中的一个接口,它是Statement的子接口。通过Statement对象执行SQL语句时,需要将SQL语句发送给DBMS,由DBMS首先进行编译后再执行。预编译语句和Statement不同,在创建PreparedStatement 对象时就指定了SQL语句,该语句立即发送给DBMS进行编译。当该编译语句被执行时,DBMS直接运行编译后的SQL语句,而不需要像其他SQL语句那样首先将其编译。
   2、什么时候使用预编译语句
   一般是在需要反复使用一个SQL语句时才使用预编译语句,预编译语句常常放在一个fo r或者while循环里面使用,通过反复设置参数从而多次使用该SQL语句。为了防止SQL注入漏洞,在某些数据操作中也使用预编译语句。
   3、为什么使用预编译语句
   预编译机制除了在开篇提到的可以防止SQL注入外,还有一下两方面的优点:
   (1)提高效率
   数据库处理一个SQL语句,需要完成解析SQL语句、检查语法和语义以及生成代码,一般说来,处理时间要比执行语句所需要的时间长。预编译语句在创建的时候已经是将指定的SQL语句发送给了DBMS,完成了解析、检查、编译等工作。因此,当一个SQL语句需要执行多次时,使用预编译语句可以减少处理时间,提高执行效率。
   (3)提高代码的可读性和可维护性
   将参数与SQL语句分离出来,这样就可以方便对程序的更改和扩展,同样,也可以减少不必要的错误。
   4、预编译语句的使用
   代码段二中创建了包含带两个 IN 参数占位符的 PreparedStatement 对象,在执行之前,必须设置每个 ? 参数的值。这可通过调用 setXXX 方法来完成,该方法的第一个参数是要设置的参数的序数位置,第二个参数是设置给该参数的值,其中 XXX 是与该参数相应的类型。例如,以下代码将第一个参数设为 “tom”,第二个参数设为 “123456a”:
   pstmt.setString(1, “tom”);
   pstmt.setString(2, “123456a”);
   一旦设置了给定语句的参数值,其值将一直保留,直到被设置为新值或者调用clearParameters()方法清除它为止。
   问题延伸:请大家看一下以下的代码:
    String sqlSt = “sel ect* from table1 where name=”+tb_name+” and passwo rd=”+tb_pwo rd;
   PrepareStatement pst = con.createPreparementStatement();
   ResultSet rsPst = pst.exe cuteQuery(sqlSt);
 

    那么在安全性和执行效率方面会不会有问题呢?请感兴趣的同事可以自己尝试一下吧。