`
datuo
  • 浏览: 82311 次
  • 性别: Icon_minigender_1
  • 来自: 成都
社区版块
存档分类
最新评论

PreparedStatement是如何大幅度提高性能的

阅读更多
 
PreparedStatement是如何大幅度提高性能的
 
作者:Billy Newport
 
本文讲述了如何正确的使用prepared statements。为什么它可以让你的应用程序运行的更快,和同样的让数据库操作变的更快。
 
 
为什么Prepared Statements非常重要?如何正确的使用它?
 
数据库有着非常艰苦的工作。它们接受来自众多并发的客户端所发出的SQL查询,并尽可能快的执行查询并返回结果。处理statements是一个开销昂贵的操作,不过现在有了Prepared Statements这样的方法,可以将这种开销降到最低。可是这种优化需要开发者来完成。所以本文会为大家展示如何正确的使用Prepared Statements才能使数据库操作达到最优化。
 
 
数据库是如何执行一个statement的?
 
显然,我不会在这里写出很多的细节,我们只关注最关键的部分。当一个数据库收到一个statement后,数据库引擎会先解析statement,然后检查其是否有语法错误。一旦statement被正确的解析,数据库会选出执行statement的最优途径。遗憾的是这个计算开销非常昂贵。数据库会首先检查是否有相关的索引可以对此提供帮助,不管是否会将一个表中的全部行都读出来。数据库对数据进行统计,然后选出最优途径。当决创建查询方案后,数据库引擎会将它执行。
 
存取方案(Access Plan)的生成会占用相当多的CPU。理想的情况是,当我们多次发送一个statement到数据库,数据库应该对statement的存取方案进行重用。如果方案曾经被生成过的话,这将减少CPU的使用率。
 
 
Statement Caches
 
数据库已经具有了类似的功能。它们通常会用如下方法对statement进行缓存。使用statement本身作为key并将存取方案存入与statement对应的缓存中。这样数据库引擎就可以对曾经执行过的statements中的存取方案进行重用。举个例子,如果我们发送一条包含SELECT a, b FROM t WHERE c = 2statement到数据库,然后首先会将存取方案进行缓存。当我们再次发送相同的statement时,数据库会对先前使用过的存取方案进行重用,这样就降低了CPU的开销。
 
注意,这里使用了整个statementkey。也就是说,如果我们发送一个包含SELECT a, b FROM t WHERE c = 3statement的话,缓存中不会没有与之对应的存取方案。这是因为“c=3”与曾经被缓存过的“c=2”不同。所以,举个例子:
 
for (int i = 0; i < 1000; i++)  {
PreparedStatement ps = conn.prepareStatement("select a,b from t where c = " + i);
ResultSet rs = Ps.executeQuery();
rs.close();
ps.close();
}
 
在这里缓存不会被使用,因为每一次迭代都会发送一条包含不同SQL语句的statement给数据库。并且每一次迭代都会生成一个新的存取方案。现在让我们来看看下一段代码:
 
PreparedStatement ps = conn.prepareStatement("select a,b from t where c = ?");
for (int i = 0; i < 1000; i++)  {
ps.setInt(1, i);
ResultSet rs = ps.executeQuery();
rs.close();
ps.close();
}
 
这样就具有了更好的效率,这个statement发送给数据库的是一条带有参数“?”的SQL语句。这样每次迭代会发送相同的statement到数据库,只是参数“c=?”不同。这种方法允许数据库重用statement的存取方案,这样就具有了更好的效率。这可以让你的应用程序速度更快,并且使用更少的CPU,这样数据库服务器就可以为更多的人提供服务。
 
 
PreparedStatementJ2EE服务器
 
当我们使用J2EE服务器时事情会变的比较复杂。通常,一个perpared statement会同一个单独的数据库连接相关联。当数据库连接被关闭时prepared statement也会被丢弃。通常,一个胖客户端会获取一个数据库连接并将其一直保持到退出。它会用“饿汉”(eagerly)或“懒汉”(lazily)方式创建所有的parepared statements。“饿汉”方式会在应用启动时创建一切。“懒汉”方式意味着只有在使用的时候才去创建。“饿汉”方式会使应用程序在启动的时候梢有延迟,但一旦启动后就会运行的相当理想。“懒汉”方式使应用程序启动速度非常快(但不会做任何准备工作),当需要使用prepared statement的时候再去创建。这样,在创建全部statement的过程中,性能是非常不稳定的,但一旦创建了所有statement后,它会像“饿汉”式应用程序一样具有很好的运行效果。请根据你的需要来选择最好的方式,是快速启动?还是前后一致的性能。
 
J2EE应用的问题是它不会像这样工作,连接只会在请求期间被保持。那意味着必须每一次请求的时候都创建prepared statement。这远没有胖客户端那种一直保持prepared statement的执行性能好。J2EE厂商已经注意到了这个问题,并且提供了连接池(ConnectionPool)以避免这种问题。
 
J2EE服务器提供了一个连接给你的应用程序时,其实它并没有给你真正的数据库连接,你只是获得了一个包装器(Wrapper)。你可以去看看你所获得的连接的类名以证实这一点。它并不是一个JDBC连接,而是一个由应用服务器创建的类。所有的JDBC操作都会被应用服务器的连接池管理器所代理。所有的JDBC ResultSetsstatementsCallableStatementspreparedStatements等都会被包装并以一个“代理对象”(Proxy Object)的形式返回给应用程序。当你关闭了连接,这些对象会被标记为失效,并被垃圾回收器所回收。
 
通常,如果你对一个数据库连接执行close,那这个连接会被JDBC驱动程序关闭。但我们需要在J2EE服务器执行close的时候数据库连接会被返回连接池。我们可以创建一个像真正的连接一样的JDBC Connection代理类来解决这个问题。它有一个对真正连接的引用。当我们执行一个连接上的方法时,代理会将操作转给真正的连接。但是,当我们对一个连接执行close时,这个连接并不会关闭,而是会送回连接池,并可以被其他请求所使用。一个已被准备过的prepared statement也会因此而得到重用。
 
 
J2EE PreparedStatement Cache
 
J2EE服务器的连接池管理器已经实现了缓存的使用。J2EE服务器保持着连接池中每一个连接准备过的prepared statement列表。当我们在一个连接上调用preparedStatement时,应用服务器会检查这个statement是否曾经准备过。如果是,这个PreparedStatement会被返回给应用程序。如果否,调用会被转给JDBC驱动程序,然后将新生成的statement对象存入连接缓存。
 
每个连接都有一个缓存的原因是因为:JDBC驱动程序就是这样工作的。任何prepared statement都是由指定的连接所返回的。
 
如果我们想利用这个缓存的优势,那就如前面所说的,使用参数化的查询语句可以在缓存中找到曾经使用过的statement。大部分应用服务器允许你调整prepared statements缓存的大小。
 
 
摘要
 
我们绝对应该使用包含参数化的查询语句的prepared statement。这样数据库就会重用准备过的存取方案。缓存适用于整个数据库,所以,如果你安排所有的应用程序使用相同的参数化SQL语句,然后你的其他应用程序就可以重用被准备过的prepared statement。这是应用服务器的一个优势,因为所有的数据库操作都集中在数据库操作层(Database Access Layer,包括O/R映射,实体BeanJDBC等)。
 
第二,正确的使用prepared statement也是利用prepared statement的缓存优势的关键。由于应用程序可以重用准备过的prepared statement,也就减少了调用JDBC驱动程序的次数,从而提高了应用程序的性能。这样就拥有了可以与胖客户端比肩的效率,却又不需要总维持一个连接。
 
使用参数化的prepared statement,你的应用程序会具有更好的性能。
 
分享到:
评论

相关推荐

    【性能】JDBC PreparedStatement和连接池PreparedStatement Cache学习记录

    1. **性能优化**:`PreparedStatement`的SQL语句在首次执行时会被数据库预编译,后续的执行只需传入参数即可,避免了每次执行SQL时的解析过程,从而提高了执行速度。 2. **防止SQL注入**:通过设置参数,可以防止...

    Statement和PreparedStatement之间的区别

    Statement和PreparedStatement之间的区别 Statement和PreparedStatement...结论:在 JDBC 应用中,建议使用PreparedStatement对象来代替Statement对象,以提高执行速度、避免SQL注入攻击和提高代码可读性和可维护性。

    PreparedStatement 详细用法

    尤其在处理动态查询或频繁执行相同SQL的情况下,`PreparedStatement`可以显著提高性能。 本文将详细介绍`PreparedStatement`的使用方法,主要面向Java服务器页面(JSP)的初学者。 #### 二、准备工作 为了能够...

    PreparedStatement

    jdbc2.0版 PreparedStatement接口的用法

    PreparedStatement详细用法

    在Java应用程序与数据库交互的过程中,`PreparedStatement`的使用能够显著提升应用程序的性能和安全性。 #### 二、PreparedStatement的优势 **1. 性能提升** - **预编译机制**:`PreparedStatement`允许将SQL...

    如何获得PreparedStatement最终执行的sql语句

    当我们处理大量重复的SQL操作时,使用`PreparedStatement`可以避免SQL注入等问题,同时提升性能。这篇博客可能是探讨如何在实际运行中获取`PreparedStatement`最终执行的SQL语句,这对于调试和分析数据库操作非常有...

    PreparedStatement和Statement

    在追求性能、安全性和代码可读性时,`PreparedStatement`通常是更好的选择,而`Statement`适用于简单的、一次性执行的SQL语句。理解并适当地使用这两种接口对于编写高效且安全的Java数据库应用程序至关重要。

    connection 和 preparedstatement 的关闭问题

    - 执行写操作(插入、更新、删除)时,以提高安全性和性能。 - 需要参数化SQL语句时,特别是为了防止SQL注入攻击。 #### 关闭策略 - **Connection**:连接是最宝贵的资源之一,应该在业务逻辑完成后尽快关闭。通常...

    java中PreparedStatement和Statement的区别

    第四,PreparedStatement 可以极大地提高安全性。使用 PreparedStatement 可以避免 SQL 注入攻击,例如: ```java String sql = "select * from tb_name where name= '"+varname+"' and passwd='"+varpasswd+"'"; ``...

    JDBC基础教程之PreparedStatement.doc

    通过以上介绍可以看出,`PreparedStatement`不仅可以提高执行SQL语句的效率,还能有效防止SQL注入攻击,因为它使用参数化查询而非字符串拼接的方式构建SQL语句。因此,在开发涉及数据库操作的应用程序时,推荐优先...

    练习3:使用PreparedStatement插入宠物信息.zip

    这可以提高性能,因为数据库可以预先编译SQL语句,然后多次执行,而无需每次都解析它。此外,由于PreparedStatement使用占位符,它能自动处理特殊字符,从而避免了SQL注入攻击的可能性。 在执行插入操作时,我们...

    关于PreparedStatement插入Date类型值的方法.txt

    这不仅能够提高应用程序的性能,还能提高安全性,因为它支持参数化查询,避免了SQL注入的风险。 #### 二、插入Date类型值的方法 ##### 2.1 `setDate()`方法 `setDate()`方法用于设置SQL语句中的`DATE`类型的参数...

    PreparedStatement 向数据库插入时间方法

    ### PreparedStatement 向数据库插入时间方法 #### 背景与问题描述 在Java应用程序中,我们经常需要将数据写入数据库。为了确保SQL查询的安全性和效率,通常会使用`PreparedStatement`来执行这样的操作。然而,在...

    PreparedStatement接口

    NULL 博文链接:https://chaoyi.iteye.com/blog/2088080

    【IT十八掌徐培成】Java基础第23天-02.sql注入-preparedstatement-批量插入.zip

    同时,熟练运用PreparedStatement的批量插入功能,可以有效地提高数据库操作的效率,尤其在处理大数据量场景时显得尤为重要。在实际项目中,结合最佳实践,如合理设置批处理大小,能够进一步优化系统性能。

    MySql练习3:使用PreparedStatement插入宠物信息.zip

    MySql练习3:使用PreparedStatement插入宠物信息.zip MySql练习3:使用PreparedStatement插入宠物信息.zip MySql练习3:使用PreparedStatement插入宠物信息.zip

    JSP中的PreparedStatement对象操作数据库的使用教程

    通过以上的步骤,我们可以看到PreparedStatement对象不仅提高了数据库操作的性能,同时增加了代码的安全性。因为预编译的SQL语句可以防止SQL注入攻击,同时通过setXXX方法的参数绑定机制避免了拼接SQL字符串的风险。...

    Java数据库连接PreparedStatement的使用详解

    1. 提高执行效率:PreparedStatement 有预编译的功能,能够在执行之前将 SQL 语句编译成机器码,从而提高执行效率。 2. 防止 SQL 注入:PreparedStatement 可以防止 SQL 注入攻击,因为它使用参数绑定,而不是将用户...

    【IT十八掌徐培成】Java基础第23天-02.sql注入-preparedstatement-批量插入 - 副本.zip

    在处理大量数据插入时,频繁地调用Statement对象的executeUpdate方法会带来很大的性能开销。为了解决这个问题,PreparedStatement支持批量操作,可以一次提交多条插入语句。批量插入的语法如下: ```java String ...

Global site tag (gtag.js) - Google Analytics