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

java 专栏收录该内容
7 篇文章 0 订阅

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

bootcool@263.net

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

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

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

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

以下是执行1000次语句结构相同的Insert,UpdateSelect语句的测试结果

 

接口类型

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

 

  我们还要注意一点,如果使用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();
        }    
  }
 }

 

以下是相关的测试结果:

方式

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();
   }
  }
}

  • 0
    点赞
  • 0
    评论
  • 0
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

相关推荐
<p style="color:#666666;"> <span style="font-size:14px;">本门课程重实战,将基础知识拆解到项目里,让你在项目情境里学知识。</span> </p> <p style="color:#666666;"> <span style="font-size:14px;">这样学习方式能让你保持兴趣、充满动力,时刻知道学东西能用在哪、能怎么用。</span> </p> <p style="color:#666666;"> <span style="font-size:14px;">平时不明白知识点,放在项目里去理解就恍然大悟了。</span> </p> <p style="color:#666666;"> <span></span> </p> <p style="color:#666666;"> <span style="font-size:14px;"> </span> </p> <p style="color:#666666;"> <span style="color:#FF0000;font-size:14px;"><strong>一、融汇贯通</strong></span> </p> <p style="color:#666666;"> <span style="font-size:14px;">本视频采用了前后端分离开发模式,前端使用Vue.js+Element UI实现了Web页面呈现,后端使用Python Django框架实现了数据访问接口,前端通过Axios访问后端接口获得数据。在学习完本章节后,真正理解前后端各自承担工作。</span> </p> <p style="color:#666666;"> <span style="font-size:14px;"> </span> </p> <p style="color:#666666;"> <span style="color:#FF0000;font-size:14px;"><strong>二、贴近实战</strong></span> </p> <p style="color:#666666;"> <span style="font-size:14px;">本系列课程为练手项目实战:学生管理系统v4.0开发,项目包含了如下几个内容:项目总体介绍、基本功能演示、Vuejs初始化、Element UI使用、在Django中实现针对数据增删改查接口、在Vuejs中实现前端增删改查调用、实现文件上传、实现表格分页、实现导出数据到Excel、实现通过Excel导入数据、实现针对表格批量化操作等等,所有功能都通过演示完成、贴近了实战</span> </p> <p style="color:#666666;"> <span style="font-size:14px;"> </span> </p> <p style="color:#666666;"> <span style="color:#FF0000;font-size:14px;"><strong>三、课程亮点</strong></span> </p> <p style="color:#666666;"> <span style="font-size:14px;">在本案例中,最大亮点在于前后端做了分离,真正理解前后端各自承担工作。前端如何和后端交互</span> </p> <p style="color:#666666;"> <span style="font-size:14px;"> </span> </p> <p style="color:#666666;"> <span style="color:#FF0000;font-size:14px;"><strong>适合人群:</strong></span> </p> <p style="color:#666666;"> <span style="font-size:14px;">1、有Python语言基础、web前端基础,想要深入学习Python Web框架朋友;</span> </p> <p style="color:#666666;"> <span style="font-size:14px;">2、有Django基础,但是想学习企业级项目实战朋友;</span> </p> <p style="color:#666666;"> <span style="font-size:14px;">3、有MySQL数据库基础朋友</span> </p> <p style="color:#666666;"> <span style="font-size:14px;"> </span> </p> <p style="color:#666666;"> <span style="font-size:14px;"><img alt="" src="https://img-bss.csdnimg.cn/202009070752197496.png" /><br /> </span> </p> <p style="color:#666666;"> <span style="font-size:14px;"><br /> </span> </p>
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值