SQL预编译

http://www.cnblogs.com/ygj0930/p/5876951.html
http://www.importnew.com/5006.html
在JDBC编程中,常用Statement、PreparedStatement 和 CallableStatement三种方式来执行查询语句,其中 Statement 用于通用查询, PreparedStatement 用于执行参数化查询,而 CallableStatement则是用于存储过程。

  1、Statement 
  该对象用于执行静态的 SQL 语句,并且返回执行结果。 此处的SQL语句必须是完整的,有明确的数据指示。查的是哪条记录?改的是哪条记录?都要指示清楚。
 通过调用 Connection 对象的 createStatement 方法创建该对象 

查询:ResultSet excuteQuery(String sql)——返回查询结果的封装对象ResultSet. 用next()遍历结果集,getXX()获取记录数据。
修改、删除、增加:int excuteUpdate(String sql)——返回影响的数据表记录数.

  2、PreparedStatement 
SQL 语句被预编译并存储在 PreparedStatement 对象中。然后可以使用此对象多次高效地执行该语句。 
可以通过调用 Connection 对象的 preparedStatement() 方法获取 PreparedStatement 对象 
PreparedStatement 对象所执行的 SQL 语句中,参数用问号(?)来表示,调用 PreparedStatement 对象的 setXXX() 方法来设置这些参数. setXXX() 方法有两个参数,第一个参数是要设置的 SQL 语句中的参数的索引(从 1 开始),第二个是设置的 SQL 语句中的参数的值,注意用setXXX方式设置时,需要与数据库中的字段类型对应,例如mysql中字段为varchar,就需要使用setString方法,如果为Date类型,就需要使用setDate方法来设置具体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查询代码为:

strSQL = "SELECT * FROM users WHERE name = '" + userName + "' and pw = '"+ passWord +"';"
恶意填入:
userName = "1' OR '1'='1";
passWord = "1' OR '1'='1";

那么最终SQL语句变成了:

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

因为WHERE条件恒为真,这就相当于执行:

strSQL = "SELECT * FROM users;"

因此可以达到无账号密码亦可登录网站。

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

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

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

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

在学习数据库编程时,我们都知道在执行SQL命令时,有二种选择:

可以使用PreparedStatement对象,

也可以使用Statement对象。

而熟悉JDBC编程的大侠们都会选择使用PreparedStatement对象,主要因为使用预编译对象PreparedStatement时,有以下几个优点:

首先是效率性

 PreparedStatement 可以尽可能的提高访问数据库的性能,我们都知道数据库在处理SQL语句时都有一个预编译的过程,而预编译对象就是把一些格式固定的SQL编译后,存放在内存池中即数据库缓冲池,当我们再次执行相同的SQL语句时就不需要预编译的过程了,只需DBMS运行SQL语句。所以当你需要执行Statement对象多次的时候,PreparedStatement对象将会大大降低运行时间,特别是的大型的数据库中,它可以有效的也加快了访问数据库的速度。
其次,使用PreparedStatement对象可以大大提高代码的可读性和可维护性。

Mysql支持预编译,只是默认没开启。
oracle里面除了查询结果集缓存外,还有SQL缓存。

语句缓存的好处
• ORACLE执行SQL语句时,先将SQL语句的字串通过一个哈希算法得出一个哈希值,然后检查共享池中是否已存在这个哈希值,若有就用已缓存的执行计划来执行这个语句(CACHE HIT 缓存命中),若没有(CACHE MISS 缓存缺失)则需进行解析,解析需要完成下面的工作:

Ø 语法检查;
Ø 语义检查,看参考对象是否存在,类型是否正确;
Ø (如果是CBO优化模式)收集参考对象的统计;
Ø 检查用户的权限是否足够;
Ø 从许多可能的执行路径中选择一条作为执行计划;
Ø 生成语句的编译版本(P-CODE)。

• 解析是一个昂贵的操作,因为过程中需要消耗许多资源;
• 最大化CACHE HIT是调整共享池的目标

发布了26 篇原创文章 · 获赞 1 · 访问量 2万+
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 编程工作室 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览