分享
 
 
 

如何测定JDBC的性能(上)

王朝other·作者佚名  2008-05-19
窄屏简体版  字體: |||超大  

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

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

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有