使用BoneCP连接池出现异常 内存泄露
我是在Tomcat中配置了JNDI,然后每次查询数据库时用下面两个类SqlConnection和SqlConnection来实现:
package db;
import java.sql.Connection;
import java.sql.SQLException;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.sql.DataSource;
import com.mysql.jdbc.*;
/*
*使用数据库连接池,具体配置在%catalinahome%/conf/sever.xml的<context><resource>节点中
*/
public class SqlConnection {
private DataSource ds = null;
Connection conn =null;
public SqlConnection(){
//通过JNDI获得数据源
try {
InitialContext ctx=null;
ctx = new InitialContext();
ds=(DataSource)ctx.lookup("java:comp/env/jdbc/lxtjngJNDI");
} catch (NamingException e) {
e.printStackTrace();
}
}
public Connection getConnection() {
try{
return conn=ds.getConnection();
}catch(Exception ex){
System.out.print("数据库连接池初始化异常,信息是:"+ex.getMessage());
ex.printStackTrace();
return null;
}
}
// /////////////////////////////////////////////////////////////////////////////
/**
* 关闭连接
*/
public void close() {
try {
if (conn != null) {
conn.close();
conn = null;
}
} catch (SQLException se) {
System.out.println("close error: " + se.getMessage());
}
finally {
// Always make sure result sets and statements are closed,
// and the connection is returned to the pool
if (conn != null) {
try { conn.close(); } catch (SQLException e) {e.printStackTrace(); }
conn = null;
}
}
}
}
//////另一个类////////////////////////////////////////
package db;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class SqlExe {
ResultSet rs =null;
Statement stmt=null;
int count = 0;// 结果记录集中记录条数
String errorMsg = "";
public SqlExe() {
}
// 执行查询语句的函数
// para sql:数据库查询语句体sql
// return ResultSet
public ResultSet executeQuery(String sql,Connection conn) {
try{
stmt = conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,ResultSet.CONCUR_UPDATABLE);
rs = stmt.executeQuery(sql);
}
catch(SQLException ex){
System.err.println("数据库查询失败in db.executeQuery: sql="+sql +"rn"+ ex.getMessage());
this.errorMsg = "查询数据失败!sql="+sql +"rn"+ ex.getMessage();
this.close();
}
return rs;
}
// /////////////////////////////////////////////////////////////////////////
/*----------执行数据库更改(增加、删除、替换)操作,返回boolean,表示是否更改成功--------------------///
*/
public boolean executeUpdate(String sql,Connection conn) {
boolean bupdate = false;
rs = null;
try {
stmt = conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,
ResultSet.CONCUR_UPDATABLE);
int rowCount = stmt.executeUpdate(sql);// 如果不成功,bupdate就会返回0
if (rowCount != 0) {
bupdate = true;
this.count = rowCount;
}
} catch (SQLException ex) {
System.err.println("数据库更新db.executeUpdate失败: sql="+sql +"rn"+ ex.getMessage());
this.errorMsg = "查询数据失败!sql="+sql +"rn"+ ex.getMessage();
this.close();
this.count =-1;
}
/*finally{
this.close();
}*/
return bupdate;
}
/*-----------------------执行数据库更改(增加、删除、替换)操作,返回所操作的行数------------------------///
*/
public int exeUpdate(String sql,Connection conn, String errorMsg) {
rs = null;
try {
stmt = conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,
ResultSet.CONCUR_UPDATABLE);
int rowCount = stmt.executeUpdate(sql);
return this.count = rowCount;
} catch (SQLException ex) {// 如果不成功,bupdate就会返回-1
System.err.println("数据库更新db.executeUpdate失败: sql="+sql+"rn"+ ex.getMessage());
this.close();
if (errorMsg == null || errorMsg.length() == 0) {
this.errorMsg = "查询数据失败!sql="+sql +"rn"+ ex.getMessage();
} else
this.errorMsg = errorMsg;
return this.count =-1;
}
/*finally{
this.close();
}
*/
}
// /////////////////////////////////////////////////////////////////////////////
/**
* 关闭连接
*/
public void close() {
try {
if (rs != null) {
rs.close();
rs = null;
}
if (stmt != null) {
stmt.close();
stmt = null;
}
} catch (SQLException se) {
System.out.println("close error: " + se.getMessage());
} finally {
if (rs != null) {
try { rs.close(); } catch (SQLException e) { ; }
rs = null;
}
if (stmt != null) {
try { stmt.close(); } catch (SQLException e) { ; }
stmt = null;
}
}
}
}
/////////////////////////////////////////////////////
下面是调用这两个类来实现数据库查询
Connection conn = new SqlConnection().getConnection();
SqlExe sqlExe = new SqlExe();
if (null != conn) {
ResultSet rsGg=sqlExe.executeQuery(sql,conn);
if(rsGg.next()){
out.print(rsGg.getString("code"));}
else{
out.print("广告burnmeSec950-90-1");
}
rsGg.close();
}
sqlExe.close();conn.close();
/////////////////////////////////////////
从调用来看,我关闭了ResultSet,Statement和Connection对象,但是BoneCp提示我有未关闭的连接,并且程序运行非常缓慢,占用内存非常高,最终宕机。
请教高手,我的做法哪里错了,为什么存在内存泄露?最好指出具体语句或方法,以及该如何改正,谢谢!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(9)
如果有较完整的数据库连接池使用的例子(最好从jndi配置到封装再到数据多次操作,不是一次性操作,即没有重用功能的连接池使用,那样好象没有实际意义------谁会每进行一次查询都重复那些语句?),请发一份burnme@qq.com,不胜感激!
如果有较完整的数据库连接池使用的例子(最好从jndi配置到封装再到数据多次操作,不是一次性操作,即没有重用功能的连接池使用,那样好象没有实际意义------谁会每进行一次查询都重复那些语句?),请发一份burnme@qq.com,不胜感激!
不过改进以后还是不行啊,在本地运行,计数器正常,每个连接截取和关闭都能正确+1和-1,但是放到服务器还是不能正确计数,有时加了好多个数才减1个数,导致连接数量暴涨,还是有内存泄露,最终还是宕机了。而且tomcat一启动,内存或CPU迅速高升,几乎到100%,但是我却没有打开任何程序,这是什么原因啊?请高手指点!
我表示你可以用mybatis 或者hibernate等框架进行持久化自己操作jdbc 容易出错
经过测试,确实没有关闭连接!原因是:我用的是Connection 对象关闭,而不是用连接池的Connection(也就是SqlConnection),所以,那个close()根本就没调用到!
谢谢Wendal!
谢谢您的提示,我试试看能不能找到问题症结,呆会将结果放上。并请继续跟进,帮助解决,谢谢!
代码没缩进,没高亮,看得眼都疼
如果你觉得是连接池的问题,那么就先不用连接池试试嘛
既然他说有连接没关, 那就自行计数一下, getConnection的时候+1, close的时候-1, 查查哪里没把连接掉