April.H.X 发表于 2007-5-10 11:49:21

(zt)J2EE程序的性能优化技巧(4)

六、数据库访问

  在J2EE开发的应用系统中,数据库访问一般是个必备的环节。数据库用来存储业务数据,供应用程序访问。

  在Java技术的应用体系中,应用程序是通过JDBC(Java Database Connectivity)实现的接口来访问数据库的,JDBC支持“建立连接、SQL语句查询、处理结果”等基本功能。在应用JDBC接口访问数据库的过程中,只要根据规范来实现,就可以达到要求的功能。

  但是,有些时候进行数据查询的效率着实让开发人员不如所愿,明明根据规范编写的程序,运行效果却很差,造成整个系统的执行效率不高。

  ·使用速度快的JDBC驱动

  JDBC API包括两种实现接口形式,一种是纯Java实现的驱动,一种利用ODBC驱动和数据库客户端实现,具体有四种驱动模式并各有不同的应用范围,针对不同的应用开发要选择合适的JDBC驱动,在同一个应用系统中,如果选择不同的JDBC驱动,在效率上会有差别。

  例如,有一个企业应用系统,不要求支持不同厂商的数据库,这时就可以选择模式4的JDBC驱动,该驱动一般由数据库厂商实现的基于本地协议的驱动,直接调用数据库管理系统使用的协议,减少了模式3中的中间层。

  ·使用JDBC连接池

  为了提高访问数据库的性能,我们还可以使用JDBC 2.0的一些规范和特性,JDBC是占用资源的,在使用数据库连接时可以使用连接池Connection Pooling,避免频繁打开、关闭Connection。而我们知道,获取Connection是比较消耗系统资源的。

  Connection缓冲池是这样工作的:当一个应用程序关闭一个数据库连接时,这个连接并不真正释放而是被循环利用,建立连接是消耗较大的操作,循环利用连接可以显著的提高性能,因为可以减少新连接的建立。

  一个通过DataSource获取缓冲池获得连接,并连接到一个CustomerDB数据源的代码演示如下:

Context ctx = new InitialContext();
DataSource dataSource = (DataSource) ctx.lookup("jdbc/CustomerDB");
Connection conn = dataSource.getConnection("password","username");

  ·缓存DataSource

  一个DataSource对象代表一个实际的数据源。这个数据源可以是从关系数据库到表格形式的文件,完全依赖于它是怎样实现的,一个数据源对象注册到JNDI名字服务后,应用程序就可以从JNDI服务器上取得该对象,并使用之和数据源建立连接。

  通过上面的例子,我们知道DataSource是从连接池获得连接的一种方式,通过JNDI方式获得,是占用资源的。

  为了避免再次的JNDI调用,可以系统中缓存要使用的DataSource。

  ·关闭所有使用的资源

  系统一般是并发的系统,在每次申请和使用完资源后,应该释放供别人使用,数据库资源每个模式的含义可以参考SUN JDBC的文档,不同是比较宝贵的,使用完成后应该保证彻底的释放。

  请看下面的代码段:

Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
try {
 DataSource dataSource = getDataSource();
 // 取的DataSource的方法,实现略。
 conn = datasource.getConnection();
 stmt = conn.createStatement();
 rs = stmt.executeQuery("SELECT * FROM ...");
 ... // 其他处理
 rs.close();
 stmt.close();
 conn.close();
}catch (SQLException ex) {
 ... // 错误处理
}

  粗看似乎没有什么问题,也有关闭相关如Connection等系统资源的代码,但当出现异常后,关闭资源的代码可能并不被执行,为保证资源的确实已被关闭,应该把资源关闭的代码放到finally块:

Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
try {
 DataSource dataSource = getDataSource();
 // 取的DataSource的方法,实现略。
 conn = datasource.getConnection();
 stmt = conn.createStatement();
 rs = stmt.executeQuery("SELECT * FROM ...");

 ... // 其他处理
}catch (SQLException ex) {
 ... // 错误处理

}finally{
 if (rs!=null) {
  try {
   rs.close(); // 关闭ResultSet}
  catch (SQLException ex) {
   ... // 错误处理
  }
 }

 if (stmt!=null){
  try {
   stmt.close(); // 关闭Statement}
  catch (SQLException ex) {
   ... // 错误处理
  }
 }
 if (conn!=null){
  try {
   conn.close(); // 关闭Connection}
  catch (SQLException ex) {
   ... // 错误处理
  }
 }
}

  ·大型数据量处理

  当我们在读取诸如数据列表、报表等大量数据时,可以发现使用EJB的方法是非常慢的,这时可以使用直接访问数据库的方法,用SQL直接存取数据,从而消除EJB的经常开支(例如远程方法调用、事务管理和数据序列化,对象的构造等)。

  ·缓存经常使用的数据

  对于构建的业务系统,如果有些数据要经常要从数据库中读取,同时,这些数据又不经常变化,这些数据就可以在系统中缓存起来,使用时直接读取缓存,而不用频繁的访问数据库读取数据。

  缓存工作可以在系统初始化时一次性读取数据,特别是一些只读的数据,当数据更新时更新数据库内容,同时更新缓存的数据值。

  一个例子是,在一套企业应用系统中,企业的信息数据(如企业的名称)在多个业务应用模块中使用,这时就可以把这些数据缓存起来,需要时直接读取缓存的企业信息数据。

  七、总结

  一般意义上说,参与系统运行的代码都会对性能产生影响,实际应用中应该养成良好的编程规范、编写高质量的代码,当系统性能出现问题时,要找到主要影响性能的瓶颈所在,然后集中精力优化这些代码,能达到事半功倍的效果。

  J2EE性能的优化包括很多方面的,要达到一个性能优良的系统,除了关注代码之外,还应该根据系统实际的运行情况,从服务器软硬件环境、集群技术、系统构架设计、系统部署环境、数据结构、算法设计等方面综合考虑。
页: [1]
查看完整版本: (zt)J2EE程序的性能优化技巧(4)