|
六、数据库访问
在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性能的优化包括很多方面的,要达到一个性能优良的系统,除了关注代码之外,还应该根据系统实际的运行情况,从服务器软硬件环境、集群技术、系统构架设计、系统部署环境、数据结构、算法设计等方面综合考虑。 |
|