1.1 概述
在JAVAEE后台编码时,时常出现没有正确及时关闭数据库连接资源(Connection,Statement, ResultSet)现象,导致程序运行过程中出现意想不到的错误。
本文档首先介绍正确使用数据库资源的方式,以此演示代码中经常出现的问题及误解。
2. 数据库资源接口
l Connection
l Statement
l ResultSet
2.1 通用的使用方式
1) 获取Connection
2) 创建Statement
3) 获取ResultSet
正确及时关闭数据库连接
1.1 概述
在JAVAEE后台编码时,时常出现没有正确及时关闭数据库连接资源(Connection,Statement, ResultSet)现象,导致程序运行过程中出现意想不到的错误。
本文档首先介绍正确使用数据库资源的方式,以此演示代码中经常出现的问题及误解。
2. 数据库资源接口
l Connection
l Statement
l ResultSet
2.1 通用的使用方式
1) 获取Connection
2) 创建Statement
3) 获取ResultSet
//获取Connection
Connection conn = …;
try {
//创建Statement
Statement stm = conn.createStatement();
try {
//获取数据集
ResultSet rs = stm.executeQuery("select * from ....");
try {
//读取数据集…
} finally {
//关闭ResultSet
rs.close();
}
} finally {
//关闭Statement
stm.close();
}
} finally {
//关闭Connection
conn.close();
}
3. 读写数据库时常见的问题
3.1 认为不需要关闭数据库资源
错误的代码示例:
final ResultSet rs = DBAdapter.executeQuery(unitCode, SQL_GET_USERNAME); // 对数据集的处理 if( rs.next()){ } |
有以下原因造成没有关闭数据库连接资源:
l 不清楚数据库连接是否关闭。
这在新手中普便存在这种问题。
l 误认为容器(EJB容器或数据总线)会自动关闭。
不能过份依赖容器,因为容器关闭数据库资源的功能是有限的,且不可靠的。
3.2 没有使用正确的方法,导致没有真正关闭数据库资源
错误的代码示例:
注:DBAdapter类封装了读取和关闭数据库资源的功能
final ResultSet rs = DBAdapter.executeQuery(unitCode, SQL_GET_USERNAME); try { // 对数据集的处理 } finally { rs.close(); } |
final ResultSet rs = DBAdapter.executeQuery(unitCode, SQL_GET_USERNAME); try { // 对数据集的处理 } finally { DBAdapter.freeDBResource(rs); } |
3.3 因失误没有关闭ResultSet
这种错误主要是由于调用其他方法时,需要传递ResultSet作为参数,习惯性的创建ResultSet没有关闭。
错误的代码示例:
PreparedStatement stm = DBAdapter.prepareStatement(unitCode, sql); try { String rs = DBAdapter.resultSetToXml(stm.executeQuery()); return rs; } finally { DBAdapter.freeDBResource(stm); } |
正确的代码如下:
PreparedStatement stm = null; ResultSet rs = null; try { stm = DBAdapter.prepareStatement(unitCode, sql); rs = stm.executeQuery(); String ret = DBAdapter.resultSetToXml(rs); return ret; } finally { if (rs != null) { DBAdapter.freeDBResource(rs); } else if (stm != null) { DBAdapter.freeDBResource(stm); } } |
3.4 程序出现异常时没有关闭数据库连接
错误代码示例:
final ResultSet rs = DBAdapter.executeQuery(unitCode, SQL_GET_USERNAME); // 对数据集的处理 … DBAdapter.freeDBResource(rs); |
正确的代码如下:
final ResultSet rs = DBAdapter.executeQuery(unitCode, SQL_GET_USERNAME); try { // 对数据集的处理 … } finally { DBAdapter.freeDBResource(rs); } |
3.5 在关闭ResultSet前被重新创建
错误代码示例:
ResultSet rs = DBAdapter.executeQuery(unitCode, SQL_GET_USERNAME); try { // 对数据集的处理 … rs = DBAdapter.executeQuery(unitCode, SQL_GET_DISPLAYNAME); … } finally { DBAdapter.freeDBResource(rs); } |
正确的代码如下:
final ResultSet rs = DBAdapter.executeQuery(unitCode, SQL_GET_USERNAME); try { // 对数据集的处理 … ResultSet rsDisplay = DBAdapter.executeQuery(unitCode, SQL_GET_DISPLAYNAME); try { …… } finally { DBAdapter.freeDBResource(rsDisplay); } … } finally { DBAdapter.freeDBResource(rs); } |
注:把ResultSet变量声明为常量(final),可有效防止此类问题的产生。
3. 读写数据库时常见的问题
3.1 认为不需要关闭数据库资源
错误的代码示例:
final ResultSet rs = DBAdapter.executeQuery(unitCode, SQL_GET_USERNAME); // 对数据集的处理 if( rs.next()){ } |
有以下原因造成没有关闭数据库连接资源:
l 不清楚数据库连接是否关闭。
这在新手中普便存在这种问题。
l 误认为容器(EJB容器或数据总线)会自动关闭。
不能过份依赖容器,因为容器关闭数据库资源的功能是有限的,且不可靠的。
3.2 没有使用正确的方法,导致没有真正关闭数据库资源
错误的代码示例:
注:DBAdapter类封装了读取和关闭数据库资源的功能
final ResultSet rs = DBAdapter.executeQuery(unitCode, SQL_GET_USERNAME); try { // 对数据集的处理 } finally { rs.close(); } |
final ResultSet rs = DBAdapter.executeQuery(unitCode, SQL_GET_USERNAME); try { // 对数据集的处理 } finally { DBAdapter.freeDBResource(rs); } |
3.3 因失误没有关闭ResultSet
这种错误主要是由于调用其他方法时,需要传递ResultSet作为参数,习惯性的创建ResultSet没有关闭。
错误的代码示例:
PreparedStatement stm = DBAdapter.prepareStatement(unitCode, sql); try { String rs = DBAdapter.resultSetToXml(stm.executeQuery()); return rs; } finally { DBAdapter.freeDBResource(stm); } |
正确的代码如下:
PreparedStatement stm = null; ResultSet rs = null; try { stm = DBAdapter.prepareStatement(unitCode, sql); rs = stm.executeQuery(); String ret = DBAdapter.resultSetToXml(rs); return ret; } finally { if (rs != null) { DBAdapter.freeDBResource(rs); } else if (stm != null) { DBAdapter.freeDBResource(stm); } } |
3.4 程序出现异常时没有关闭数据库连接
错误代码示例:
final ResultSet rs = DBAdapter.executeQuery(unitCode, SQL_GET_USERNAME); // 对数据集的处理 … DBAdapter.freeDBResource(rs); |
正确的代码如下:
final ResultSet rs = DBAdapter.executeQuery(unitCode, SQL_GET_USERNAME); try { // 对数据集的处理 … } finally { DBAdapter.freeDBResource(rs); } |
3.5 在关闭ResultSet前被重新创建
错误代码示例:
ResultSet rs = DBAdapter.executeQuery(unitCode, SQL_GET_USERNAME); try { // 对数据集的处理 … rs = DBAdapter.executeQuery(unitCode, SQL_GET_DISPLAYNAME); … } finally { DBAdapter.freeDBResource(rs); } |
正确的代码如下:
final ResultSet rs = DBAdapter.executeQuery(unitCode, SQL_GET_USERNAME); try { // 对数据集的处理 … ResultSet rsDisplay = DBAdapter.executeQuery(unitCode, SQL_GET_DISPLAYNAME); try { …… } finally { DBAdapter.freeDBResource(rsDisplay); } … } finally { DBAdapter.freeDBResource(rs); } |
注:把ResultSet变量声明为常量(final),可有效防止此类问题的产生。