PreparedStatement 是什么( 二 )

< 1000; ++I) { PreparedStatement ps = conn.prepareStatement("select a,b from t where c = " + I); ResultSet rs = Ps.executeQuery(); Rs.close(); Ps.close(); } 这里不会用到缓冲. 每次循环向数据库发送一条不同的 SQL 语句. 每次循环都重新计算新的访问 方案, 用这种方法我们会浪费大量的 CPU 周期. 但是, 看看下一个片段: 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(); 这样就会高效得多. 发送给数据库的语句在 sql 中使用 @#?@# 符号来参数化. 这意味着每次循环 发送是同一条语句, 在 "c=?" 部分带有不同的参数. 这样就允许数据库重用语句的访问方案, 是程序在数据库内部运行得更高效. 这基本上能使你的程序 运行得更快, 或者使数据库用户能更多 地使用 CPU. PreparedStatement 和 J2EE 服务器当我们使用 J2EE 服务器的时候, 事情会变得更加复杂. 通常情况下, 一个预先准备好的语句 (prepared statement) 是和一个单独的数据库连接相关联的. 当连接关闭时, 语句就被丢弃 了. 一般来说, 一个胖客户端应用程序在得到一个数据库连接后会一 直保持到程序结束. 它会使用 两种方法创建所有的语句: 急切创建(eagerly) 或者 懒惰创建(lazily). Eagerly是说, 当程序启动时全部创建. Lazily是说随用随创建. 急切的方法会在程序启动时有些延时, 但是一旦程序启动以后, 运行很好. 懒惰的方法启动很快, 但是当程序运行时, 预先准备的语句在第一次使用是创建. 这就会造成性能 不平衡, 知道所有的 语句都准备好了, 但是最终程序会和急切方法一样快. 哪一种最好要看你需要的是快速启动还是 均衡的性能. 一个 J2EE 应用程序所带来的问题就是它不能像这样工作. 它只在一个请求的生存时间中保持一个 连接. 这意味着在他处理每一个请求时都会重新创建语句, 就不象胖客户端只创建一次, 而不是每 个请求都创建那样有效, 当 J2EE 服务器给你的程序一个连接时, 并不是一个真正的连接, 而是一个经过包装的. 你可以通过查看那个连接的类的名字来检验一下. 它不是一个数据库的 JDBC 连接, 是你的服务器创建 的一个类. 通常, 如果你调用一个连接的 close 方法, 那么 jdbc 驱动程序会关闭这个连接. 我们希望的是当 J2EE 应用程序调用 close 的时候, 连接会返回到连接池中. 我们通过设计一个 代理的 jdbc 连接类来做这些, 但看起来 就象是实际的连接. 当我们调用这个连接的任何方法时, 代理类就会把请求前递给 实际的连接. 但是, 当我们调用类似 close 的方法时, 并不调用实际 连接的 close 方法, 只是简单地把连接返回给连接池, 然后把代理连接标记为无效, 这样当它 被应用程序重新使用时, 我们会得到异常.包装是非常有用的, 因为它帮助J2EE 应用程序服务器实现者比较聪明地加上预先准备语句的 支持. 当程序调用Connection.prepareStatement 时, 由驱动程序返回一 个 PreparedStatement 对象. 当应用程序得到它时, 保存这个句柄, 并且在请求完成时, 关闭 请求之前关闭这个句柄. 但是, 在连接返回到连接池之后, 以后被同样或者 另一个应用程序重用时, 那么, 我们就理论上希望同样的 PreparedStatement 返回给 应用程序.

推荐阅读