JDBC编程之预编译SQL与防注入式攻击以及PreparedStatement的使用教程

    转载请注明原文地址: http://www.cnblogs.com/ygj0930/p/5876951.htmlhtml

     在JDBC编程中,经常使用Statement、PreparedStatement 和 CallableStatement三种方式来执行查询语句,其中 Statement 用于通用查询, PreparedStatement 用于执行参数化查询,而 CallableStatement则是用于存储过程。java

      一、Statement 
      该对象用于执行静态的 SQL 语句,而且返回执行结果。 此处的SQL语句必须是完整的,有明确的数据指示。查的是哪条记录?改的是哪条记录?都要指示清楚。
     经过调用 Connection 对象的 createStatement 方法建立该对象 
查询:ResultSet excuteQuery(String sql)——返回查询结果的封装对象ResultSet. 用next()遍历结果集,getXX()获取记录数据。
修改、删除、增长:int excuteUpdate(String sql)——返回影响的数据表记录数. mysql

      二、PreparedStatement 
    SQL 语句被预编译并存储在 PreparedStatement 对象中。而后可使用此对象屡次高效地执行该语句。 
    能够经过调用 Connection 对象的 preparedStatement() 方法获取 PreparedStatement 对象 
    PreparedStatement 对象所执行的 SQL 语句中,参数用问号(?)来表示,调用 PreparedStatement 对象的 setXXX() 方法来设置这些参数. setXXX() 方法有两个参数,第一个参数是要设置的 SQL 语句中的参数的索引(从 1 开始),第二个是设置的 SQL 语句中的参数的值,注意用setXXX方式设置时,须要与数据库中的字段类型对应,例如mysql中字段为varchar,就须要使用setString方法,若是为Date类型,就须要使用setDate方法来设置具体sql的参数。sql

    简单来讲就是,预编译的SQL语句不是有具体数值的语句,而是用(?)来代替具体数据,而后在执行的时候再调用setXX()方法把具体的数据传入。同时,这个语句只在第一次执行的时候编译一次,而后保存在缓存中。以后执行时,只需从缓存中抽取编译过了的代码以及新传进来的具体数据,便可得到完整的sql命令。这样一来就省下了后面每次执行时语句的编译时间。数据库

 

    使用预编译分4步走:编程

    1:定义预编译的sql语句,其中待填入的参数用  ?  占位。注意,?无关类型,不须要加分号之类。其具体数据类型在下面setXX()时决定。缓存

    2:建立预编译Statement,并把sql语句传入。此时sql语句已与此preparedStatement绑定。因此第4步执行语句时无需再把sql语句做为参数传入execute()。性能

    3:填入具体参数。经过setXX(问号下标,数值)来为sql语句填入具体数据。注意:问号下标从1开始,setXX与数值类型有关,字符串就是setString(index,str).优化

    4:执行预处理对象。主要有:网站

 boolean execute()
          在此 PreparedStatement 对象中执行 SQL 语句,该语句能够是任何种类的 SQL 语句。
 ResultSet executeQuery()
          在此 PreparedStatement 对象中执行 SQL 查询,并返回该查询生成的 ResultSet 对象。
 int executeUpdate()
          在此 PreparedStatement 对象中执行 SQL 语句,该语句必须是一个 SQL 数据操做语言(Data Manipulation Language,DML)语句,好比 INSERTUPDATEDELETE 语句;或者是无返回内容的 SQL 语句,好比 DDL 语句。

    注意,前面建立preparedstatement时已经把sql语句传入了,此时执行不需再把sql语句传入,这是与通常statement执行sql语句所不一样之处。

    好比:

     String sql="select Sname from stu where Sno=?"

     PreparedStatement prestmt = conn.prepareStatement(sql);

  prestmt.setString(1,sno);

    prestmt.executeQuery();

 

 

使用预编译的好处:

1:PreparedStatement比 Statement 更快
使用 PreparedStatement 最重要的一点好处是它拥有更佳的性能优点,SQL语句会预编译在数据库系统中。执行计划一样会被缓存起来,它容许数据库作参数化查询。使用预处理语句比普通的查询更快,由于它作的工做更少(数据库对SQL语句的分析,编译,优化已经在第一次查询前完成了)。

2:PreparedStatement能够防止SQL注入式攻击

SQL 注入攻击:SQL 注入是利用某些系统没有对用户输入的数据进行充分的检查,而在用户输入数据中注入非法的 SQL 语句段或命令,从而利用系统的 SQL 引擎完成恶意行为的作法。

好比:某个网站的登陆验证SQL查询代码为:

 

1
strSQL = "SELECT * FROM users WHERE name = '" + userName + "' and pw = '" + passWord + "';"

恶意填入:

1
2
userName = "1' OR '1'='1" ;
passWord = "1' OR '1'='1" ;

那么最终SQL语句变成了:

1
strSQL = "SELECT * FROM users WHERE name = '1' OR '1'='1' and pw = '1' OR '1'='1';"

由于WHERE条件恒为真,这就至关于执行:

1
strSQL = "SELECT * FROM users;"

所以能够达到无帐号密码亦可登陆网站。

若是恶意用户要是更坏一点,SQL语句变成

1
strSQL = "SELECT * FROM users WHERE name = 'any_value' and pw = ''; DROP TABLE users"

这样一来,虽然没有登陆,可是数据表都被删除了。

     使用PreparedStatement的参数化的查询能够阻止大部分的SQL注入。在使用参数化查询的状况下,数据库系统不会将参数的内容视为SQL指令的一部分来处理,而是在数据库完成SQL指令的编译后,才套用参数运行,所以就算参数中含有破坏性的指令,也不会被数据库所运行。由于对于参数化查询来讲,查询SQL语句的格式是已经规定好了的,须要查的数据也设置好了,缺的只是具体的那几个数据而已。因此用户能提供的只是数据,并且只能按需提供,没法更进一步作出影响数据库的其余举动来。

 

参考资料:

http://www.importnew.com/5006.html

相关文章
相关标签/搜索