国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

如何測定JDBC的性能(上)

2019-11-18 12:39:52
字體:
來源:轉載
供稿:網友

  java數據庫連接(JDBC)被廣泛用在Java應用程序中。在本篇文章中,我們將討論如何測定JDBC的性能,如何判定JDBC子系統中的哪一部分需要進行優化。
  核心的java.sql界面
  我們的目的是提高應用程序的性能。一般情況下,我們需要對應用程序進行分析,找出其中的瓶頸。當然了,要對分布式應用程序進行有效的分析是比較困難的,I/O是分析的一個重點,這是由分布式應用程序的特點決定的,分布式應用程序中的線程需要花費大量的時間等待I/O操作。目前還不清楚線程因等待讀、寫操作而阻塞是瓶頸的一部分呢還是一個無關緊要的小問題。在進行分析時,有一個獨立的通信系統測試標準是重要的。那么在測試JDBC子系統的性能時,我們應當測試哪些指標呢?
  在java.sql軟件包中,有三個接口組成了JDBC的核心:Connection、Statement和ResultSet。與數據庫的正常交互包括下面的幾部分:
  ·從數據庫驅動程序中獲得一個Connection對象。
  ·從Connection對象中獲取能夠執行指定的SQL語句的Statement對象
  ·假如SQL語句需要從數據庫中讀取數據,則使用Statement對象獲取一個提供對數據庫中的數據進行訪問的ResultSet對象。
  下面的例子通過訪問指定數據庫表的每行記錄的所有域、將每行的數據存儲到String []、并將所有的行放到一個向量中,演示了標準的數據庫交互過程。
  public static Vector getATable(String tablename, Connection Connection)
  throws SQLException
  {
  String sqlQuery = "SELECT * FROM " + tablename;
  Statement statement = Connection.createStatement();
  ResultSet resultSet = statement.executeQuery(sqlQuery);
  int numColumns = resultSet.getMetaData().getColumnCount();
  String[] aRow;
  Vector allRows = new Vector();
  while(resultSet.next())
  {
  aRow = new String[numColumns];
  for (int i = 0; i < numColumns; i++)
  file://ResultSet的訪問是從1開始的,數組是從0開始的。
  aRow[i] = resultSet.getString(i+1);
  allRows.addElement(aRow);
  }
  return allRows;
  }
  在java.sql或其他的SDK中沒有Connection、Statement和ResultSet這三個對象的具體實現,這些對象以及其他的JDBC接口都是由數據庫驅動程序的廠商開發的,并被作為數據庫驅動程序的一部分包括在驅動程序軟件包中。假如要打印出Connection對象或使用的其他對象的類名,可能會看到類似XXXConnection、XXXStatement、XXXConnectionImpl、XXXStatementImpl等字符串,其中的XXX就是正在使用的數據庫的名字,例如Oracle
  假如我們要測試例子中getATable()方法的JDBC的性能,可以簡單地在該方法的開始處和末尾處添加System.currentTimeMillis(),二者之間的時間差就是getATable()方法執行所使用的時間。只要數據庫的交互過程與其他過程沒有攪和在一起,就可以使用這種方法測試一個方法的JDBC性能。但通常情況下,Java應用程序的的數據庫交互過程分布在許多類的許多方法中,而且很難將數據庫交互過程單獨分離出來。那么在這種情況下我們應該如何測試數據庫交互過程的性能呢?
  一個理想的方法是在所有的JDBC類中都內置測量性能的能力,然后可以在需要對其性能進行監測時簡單地打開監測功能就可以了。正常情況下,JDBC類沒有提供這種能力,但我們可以使用具備這種功能的類來替換它們,我們替換類的目標是提供與PRoxy非常相似的對象。
  使用一個接口的專用封裝對象封裝該接口的對象是一種有多種用途的成熟技術,collection類同步的封裝對象就是最聞名的一個例子,但還有其他許多用途。SDK中甚至有一個專門在運行時才生成封裝對象的類:java.lang.reflect.Proxy類。封裝對象也被稱作代理對象,假如在本篇文章中使用代理對象這個術語,會使對封裝JDBC對象的解釋更復雜,因此,在本篇文章中仍然會堅持使用封裝類。
  要在上述功能的基礎上添加測試數據庫交互過程的功能,還需要對應用程序的其他部分作一些改變,很明顯的是,這樣作需要一定的代價。
  幸運的是,當一個框架象JDBC那樣幾乎完全采用接口來定義時,要用另外的實現替換其中的作一個類就相當簡單了。我們可以使用一個封裝類替換一個接口的任何一種實現,該封裝類封裝原有的類,并轉發所有對原來類的方法的調用。在本篇文章中,我們可以使用一個封裝類替換掉JDBC類,將我們監測JDBC性能的功能放置在封裝類中,然后使監測功能隨整個應用程序的執行而執行。
  封裝Connection類
  
    我們將首先討論Connection類的封裝。下面的ConnectionWrapper類實現了Connection類,該類有一個Connection類的實例變量和使用構建器的參數初始化實例變量的構建器,大多數的Connection類的方法被簡單地定義為將調用托付給實例變量:
  package tuning.jdbc;
  import java.sql.*;
  import java.util.Map;
  public class ConnectionWrapper implements Connection
  {
  protected Connection realConnection;
  public Connection realConnection () {
  return realConnection;
  }
  public ConnectionWrapper (Connection Connection) {
  realConnection = Connection;
  }
  public void clearWarnings() throws SQLException {
  realConnection.clearWarnings();
  }
  public void close() throws SQLException {
  realConnection.close();
  }
  public boolean isClosed() throws SQLException {
  return realConnection.isClosed();
  }
  public void commit() throws SQLException {
  realConnection.commit();
  }
  ...
  我省略了大部分的方法,但它們都符合下面的的模板,在需要使用從數據庫驅動程序中獲取的Connection對象的地方,我們可以簡單地使用ConnectionWrapper封裝Connection對象,而使用ConnectionWrapper對象。無論在哪里獲取了Connection對象,我們都需要在該處添加下面的二行代碼:
  Connection dbConnection = getConnectionFromDriver();
  dbConnection = new ConnectionWrapper(dbConnection);
  獲得連接是該應用程序中唯一需要改變的部分,這要求發現所有獲得一個Connection對象的調用,并對該調用進行編輯。然而,大多數的應用程序使用一個集中的代理類提供Connection對象,在這種情況下,在應用程序中使用ConnectionWrapper就非常簡單了。該代理類需要頻繁地訪問一個Connection對象池,因此在將一個Connection對象釋放回Connection對象池中時,還需要作一些額外的工作,因為Connection對象首先需要被解包,例如:
  public static void releaseConnection(Connection conn)
  {
  if (conn instanceof ConnectionWrapper)
  conn = ( (ConnectionWrapper) conn).realConnection();
  ...
  }
  我們還沒有真正地完成ConnectionWrapper類,ConnectionWrapper類中有一些方法不能簡單地托付,這些就是提供各種Statement對象的方法:
  public Statement createStatement() throws SQLException {
  return new StatementWrapper(realConnection.createStatement(), this);
  }
  public Statement createStatement(int resultSetType,
  int resultSetConcurrency) throws SQLException {
  return new StatementWrapper(
  realConnection.createStatement(resultSetType,
  resultSetConcurrency), this);
  }
  public CallableStatement prepareCall(String sql) throws SQLException {
  return new CallableStatementWrapper(
  realConnection.prepareCall(sql), this, sql);
  }
  public CallableStatement prepareCall(String sql, int resultSetType,
  int resultSetConcurrency) throws SQLException {
  return new CallableStatementWrapper(
  realConnection.prepareCall(sql, resultSetType,
  resultSetConcurrency), this, sql);
  }
  public PreparedStatement prepareStatement(String sql)
  throws SQLException {
  return new PreparedStatementWrapper(
  realConnection.prepareStatement(sql), this, sql);
  }
  public PreparedStatement prepareStatement(String sql, int resultSetType,
  int resultSetConcurrency) throws SQLException {
  return new PreparedStatementWrapper(
  realConnection.prepareStatement(sql, resultSetType,
  resultSetConcurrency), this, sql);
  }
  如上所示,我們需要定義三種Statement封裝類,另外,我們還需要為DatabaseMetaData定義一個封裝類,該封裝類必須是完備的,因為DatabaseMetaData能夠返回用來創建DatabaseMetaData的Connection對象,因此我們需要確保Connection對象是經過封裝過的,而不是我們沒有封裝過的Connection對象。
  public DatabaseMetaData getMetaData() throws SQLException {
  return new DatabaseMetaDataWrapper(
  realConnection.getMetaData(), this);
  }
  封裝statement類
  Statement、PreparedStatement和CallableStatement這三個statement類的封裝類相似:
  public class StatementWrapper implements Statement
  {
  protected Statement realStatement;
  protected ConnectionWrapper connectionParent;
  
  public StatementWrapper(Statemen

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 克什克腾旗| 萨嘎县| 平邑县| 沿河| 绥宁县| 颍上县| 永和县| 什邡市| 大宁县| 普陀区| 荥阳市| 崇阳县| 洪泽县| 肃北| 龙陵县| 扎囊县| 即墨市| 页游| 巫溪县| 永泰县| 怀化市| 巴楚县| 通州区| 团风县| 武城县| 建阳市| 铁力市| 阳曲县| 石家庄市| 那坡县| 丽水市| 隆德县| 油尖旺区| 元氏县| 广元市| 洪洞县| 宝山区| 临城县| 康平县| 托克托县| 曲麻莱县|