`
zhang19841017
  • 浏览: 77900 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

JDBC:预编译语句和批量更新-

阅读更多
JDBC:预编译语句和批量更新- -

                                     

进一步提高JDBC应用程序的性能 (四)

http://www.daima.com.cn/Info/55/Info15348/

bootcool@263.net

四:使用预编译语句和批量更新

首先我们得大致的了解数据库是怎么处理各种数据库操作语句的。当数据库接收到一个语句时,数据库引擎首先解析该语句,然后分析是否有语法,语义错误。如果没有错误,数据库将计算出如何高效的执行该语句。一旦得出执行策略,就由数据库引擎执行该语句,最后把执行结果反馈给用户。虽然数据库厂商对各自的数据库做了最大的优化,但是可以想象这的确是一个开销很大的工作。

于是,我们考虑如何使我们的数据库操作变得更高效呢?如果一条语句执行一次后,数据库就记录下该语句的执行策略,那么以后执行相同语句时,就可以省去上面的种种麻烦了。

Java里提供了这样的接口――PreparedStatement.。通过预编译PreparedStatement 对象, 我们能够很容易的提高语句执行效率。同时,需要指出的是Java里还有另一个实现数据库操作的接口――Statement,但是当语句格式固定时我们更倾向于使用PreparedStatement,只有当语句格式无法预见时,我们才考虑采用Statement。

以下是执行1000次语句结构相同的Insert,Update和Select语句的测试结果:



接口类型



Insert语句



Update语句



Select语句

第一次测试耗时



第二次测试耗时



第一次测试耗时



第二次测试耗时



第一次测试耗时



第二次测试耗时

Statement



2360 ms



2190 ms



3790 ms



3460 ms



3570 ms



2530 ms

PreparedStatement



1270 ms



1040 ms



2600 ms



2410 ms



440 ms



380 ms

                                     (表8)

分析: PreparedStatement 的效率明显比Statement要高出很多。另外,对于查询语句我们还得深入地看看JDBC是如何实现的。JDBC执行一次查询后,将返回一个 ResultSet(结果集)。为了建立这个结果集,JDBC将对数据库访问两次。第一次要求数据库对结果集中的各列进行说明,第二次告诉数据库,当程序需要获取数据时应如何安置这些数据。由此我们能够算出执行一次或多次查询,JDBC需要访问数据库的次数。

访问数据库次数 = 结果集中的列数 * 语句执行的次数 * 2



如果同样执行100次相同查询,结果集中的列数也相同时,假设为20列:

使用Statement:  访问数据库次数 = 20 * 100 * 2 = 4000  

使用Prepared Statement:  访问数据库次数 = 20 * 1* 2 = 400





以下是相关的测试结果:

方式



Select语句

执行100次语句结构相同的查询耗时



执行1000次语句结构相同的查询耗时

第一次测试



第二次测试



第一次测试



第二次测试

方式1



1100 ms



330 ms



3510 ms



3020 ms

方式2



110 ms



50 ms



440 ms



380 ms

                                   (表9)

分析:测试结果说明,如果不正确的使用了PreparedStatement接口,那么其执行效率和使用Statement没有什么差别,而PreparedStatement接口的优势也不会得到充分发挥。

最后我们还得补充一点,当我们需要成批插入或者更新记录时。我们考虑采用Java的批量更新机制,这一机制允许多条语句一次性提交给数据库批量处理。通常情况下比单独提交处理更有效率。如果我们再配合使用PreparedStatement接口,将进一步提高程序的性能。我们同样给出一个小程序予以说明。

import java.sql.*;

public class JDBCTEST3 {

  public static void main(String[] args) {
    try {String[] values = {"BeiJing","KunMing"};
          int[] results;

         Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
         Connection con = DriverManager.getConnection("jdbc:odbc:test");
           Statement st = con.createStatement ();
          for (int i = 0; i < values.length; i++){
             //把一个SQL命令加入命令列表
             st.addBatch ("INSERT INTO CITY VALUES('" + values[i] + "')");
          }
          //执行批量更新
          st.executeBatch ();

          PreparedStatement pst = con.prepareStatement("INSERT INTO CITY"
                                                       +"VALUES (?)");
  for (int i = 0; i < values.length; i++) {
            pst.setString(1, values[i]);
            //把一个SQL命令加入命令列表
pst.addBatch();
          }
          //执行批量更新
pst.executeBatch();
        
          st.close();
          pst.close();
          con.close();
   }
   catch(Exception ex){
    ex.printStackTrace();
   }
  }
}

  我们还要注意一点,如果使用PreparedStatement接口的方法不当,则不能达到提高执行效率的目的。我们用一个简单的测试程序说明:

import java.sql.*;
public class JDBCTEST2 {
private static Connection con = null;
private static String dbUrl = null;

public JDBCTEST2(){
}
public static void main(String args[]){
          try{
               dbUrl = "jdbc:odbc:test";
               Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
                 preparedStatementInsertTest_1();
                 System.out.println("===================");
                 preparedStatementInsertTest_2();
          }
          catch(Exception ex){
           ex.printStackTrace();
          }
  }

//方法1以不恰当的方式使用了PreparedStatement接口
public static void  preparedStatementInsertTest_1(){
      try{
            con = DriverManager.getConnection(dbUrl);
              PreparedStatement pst = null;
              long start = System.currentTimeMillis();
            
//执行1000次语句结构相同的查询
for(int i=0;i<1000;i++){
                 pst = con.prepareStatement("select * from s where s1 = " + i);
                 pst.executeQuery();
                 pst.close();
              }
              System.out.println("Methord_1 Execute Ellapse:"
                                +(System.currentTimeMillis()-start)
                                +"ms");
              con.close();
          }
        catch(Exception ex){
          ex.printStackTrace();
        }   
}

//方法2以正确的方式使用了PreparedStatement接口
public static void  preparedStatementInsertTest_2(){
      try{
            con = DriverManager.getConnection(dbUrl);
             long start = System.currentTimeMillis();
                PreparedStatement pst = null;
pst = con.prepareStatement("select * from s where s1 = ?");
              
//执行1000次语句结构相同的查询
for(int i=0;i<1000;i++){
                  pst.setInt(1,i);
                  pst.executeQuery();
              }
              System.out.println("Methord_2 Execute Ellapse:"
                                +(System.currentTimeMillis()-start)
                                +"ms");
              pst.close();
              con.close();
          }
        catch(Exception ex){
          ex.printStackTrace();
        }   
  }
}

分享到:
评论
1 楼 andyihk 2010-11-21  
lz的代码有点问题,我是照着lz的方法做的。但发现不行。应该加上
con.setAutoCommit(false)
Statement st = con.createStatement ();
          for (int i = 0; i < values.length; i++){
             //把一个SQL命令加入命令列表
             st.addBatch ("INSERT INTO CITY VALUES('" + values[i] + "')");
          }
          //执行批量更新
          st.executeBatch ();

          PreparedStatement pst = con.prepareStatement("INSERT INTO CITY"
                                                       +"VALUES (?)");
  for (int i = 0; i < values.length; i++) {
            pst.setString(1, values[i]);
            //把一个SQL命令加入命令列表
pst.addBatch();
          }
          //执行批量更新
pst.executeBatch();
con.commit();

相关推荐

    利用JDBC的PrepareStatement打印真实SQL的方法详解

    PreparedStatement是预编译的,对于批量处理可以大大提高效率. 也叫JDBC存储过程,下面这篇文章主要给大家介绍了关于利用JDBC的PrepareStatement打印真实SQL的方法,需要的朋友可以参考借鉴,下面来一起看看吧。

    每天十道面试题(五)——JDBC数据库编程部分

    1)性能方面,PreparedStatement有预编译过程,一旦绑定SQL语句就可以执行多次,Statement执行多少次就要编译多少次SQL语句。PreparedStatement用来执行动态的SQL语句,即包含参数的SQL语句,而Statement用

    java8源码-dbm:一个简单的JavaORM框架,基于spring-jdbc

    支持sql语句和接口绑定风格的DAO,但sql不是写在丑陋的xml里,而是直接写在sql文件里,这样用eclipse或者相关支持sql的编辑器打开时,就可以语法高亮,更容易阅读。 支持sql脚本修改后重新加载 内置支持分页查询。 ...

    Oracle SQL Hand-Oracle工具 v5.1.zip

    (6) 方便操作常用数据字典如表、视图、索引、过程、函数、触发器等(能显示和编辑编译PL/SQL代码); (7) 中英文双语界面并能随时切换,个性化界面设置,界面简洁清爽; (8) 运行语句“DESC tableName”清晰地显示表...

    Java数据编程指南

    SQLJ 简介 什么是SQLJ 准备开始 使用SQLJ SQLJ定制 小结 第9章 数据库性能问题 本地编译机制 挑选适当的JDBC驱动程序 连接池 事务和批量查询 存储过程和JDBC准备语句 JDBC...

    MySQL,Oracle,PostgreSQL 数据库WEB维护管理软件

    支持多语句批量执行,支持选择执行,支持关键字高亮提示,支持多结果展示。 2、选择左侧库表后,将直接查询表数据,并展示出来。可通过新增、编辑、删除按钮对表数据进行维护。也可直接对数据编辑,操作十分方便。 ...

    Java核心技术II(第8版)

    4.9.2 批量更新 4.9.3 高级SQL类型 4.10 Web与企业应用中的连接管理 4.11 LDAP介绍 4.11.1 配置LDAP服务器 4.11.2 访问LDAP目录信息 第五章 国际化 5.1 Locales 5.2 数字格式 5.2.1 货币 5.3 日期和时间 5.4 排序 ...

    疯狂JAVA讲义

    学生提问:当我们使用编译C程序时,不仅需要指定存放目标文件的位置,也需要指定目标文件的文件名,这里使用javac编译Java程序时怎么不需要指定目标文件的文件名呢? 13 1.5.3 运行Java程序 14 1.5.4 根据...

    Hibernate教程

    15.13. 批量的UPDATE & DELETE语句 15.14. 小技巧 & 小窍门 16. 条件查询(Criteria Queries) 16.1. 创建一个Criteria 实例 16.2. 限制结果集内容 16.3. 结果集排序 16.4. 关联 16.5. 动态关联抓取 16.6. 查询...

    hibernate 框架详解

    批量的UPDATE & DELETE语句 15.14. 小技巧 & 小窍门 16. 条件查询(Criteria Queries) 16.1. 创建一个Criteria 实例 16.2. 限制结果集内容 16.3. 结果集排序 16.4. 关联 16.5. 动态关联抓取 16.6. 查询示例...

    hibernate3.04中文文档.chm

    15.13. 批量的UPDATE & DELETE语句 15.14. 小技巧 & 小窍门 16. 条件查询(Criteria Queries) 16.1. 创建一个Criteria 实例 16.2. 限制结果集内容 16.3. 结果集排序 16.4. 关联 16.5. 动态关联抓取 16.6. ...

    测试培训教材

    项目管理员可以使用QC的Excel插件工具来执行需求的批量导入,进行导入之前请先确认已经访问过MQC主页,并安装了QCMSExcelAddin.exe插件。 插件下载地址: http://updates.merc-int.com/qual ... /msexcel/index.html...

    java开源包1

    MyBatchFramework 是一个开源的轻量级的用以创建可靠的易管理的批量作业的Java包,主要特点是多线程、调度、JMX管理和批量执行报表,执行历史等。 SIP协议包 jSIP.tar jSIP这个Java包目标是用Java实现SIP(SIP:...

    java开源包10

    MyBatchFramework 是一个开源的轻量级的用以创建可靠的易管理的批量作业的Java包,主要特点是多线程、调度、JMX管理和批量执行报表,执行历史等。 SIP协议包 jSIP.tar jSIP这个Java包目标是用Java实现SIP(SIP:...

    java开源包11

    MyBatchFramework 是一个开源的轻量级的用以创建可靠的易管理的批量作业的Java包,主要特点是多线程、调度、JMX管理和批量执行报表,执行历史等。 SIP协议包 jSIP.tar jSIP这个Java包目标是用Java实现SIP(SIP:...

    java开源包2

    MyBatchFramework 是一个开源的轻量级的用以创建可靠的易管理的批量作业的Java包,主要特点是多线程、调度、JMX管理和批量执行报表,执行历史等。 SIP协议包 jSIP.tar jSIP这个Java包目标是用Java实现SIP(SIP:...

    java开源包3

    MyBatchFramework 是一个开源的轻量级的用以创建可靠的易管理的批量作业的Java包,主要特点是多线程、调度、JMX管理和批量执行报表,执行历史等。 SIP协议包 jSIP.tar jSIP这个Java包目标是用Java实现SIP(SIP:...

    java开源包6

    MyBatchFramework 是一个开源的轻量级的用以创建可靠的易管理的批量作业的Java包,主要特点是多线程、调度、JMX管理和批量执行报表,执行历史等。 SIP协议包 jSIP.tar jSIP这个Java包目标是用Java实现SIP(SIP:...

Global site tag (gtag.js) - Google Analytics