最近在做java的c/s应用,用到了JDBC,由于是客户端程序没有使用线程池,而是使用直连方式。程序中有一个线程在一直读取数据库(死循环,每秒种读取一次数据库),但是程序运行半个小时左右就会虚拟机溢出,进行测试发现connection没有关闭,PreparedStatement对象也没有关闭。
很奇怪我尝试过使用常开connection连接,就是一个操作中保持一个Connection不关闭,但是PreparedStatement的数量也一直在增加,不知道为什么,还是我的程序有问题,附上代码:
数据库操作封装类:/**
* 获取数据库连接
* @return 数据库连接
*/
public static Connection createConn() {
Connection conn = null;
try {
Class.forName(DBData.DRIVER);
conn = DriverManager.getConnection(DBData.getURLForMySQL(), DBData.USER, DBData.PASSWORD);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
//JOptionPane.showMessageDialog(Source.getMainWindow(), "创建数据库连接失败,请检查服务器运行状态.");
//return createConn();
}
return conn;
}
/**
* 获取数据库Statement
* @param conn 数据库连接
* @return 数据库stmt
*/
public static Statement createStmt(Connection conn) {
Statement stmt = null;
try {
stmt = conn.createStatement();
} catch (SQLException e) {
e.printStackTrace();
}
return stmt;
}
/**
* 获取数据库PreparedStatement
* @param conn 连接
* @param sql sql语句
* @return PreparedStatement
*/
public static PreparedStatement prepare(Connection conn, String sql) {
PreparedStatement ps = null;
try {
ps = conn.prepareStatement(sql);
} catch (SQLException e) {
e.printStackTrace();
}
return ps;
}
/**
* 关闭Connection
* @param conn 数据库连接
*/
public static void close(Connection conn) {
try {
conn.close();
conn = null;
} catch (SQLException e) {
e.printStackTrace();
}
}
/**
* 关闭Statement
* @param stmt Statement
*/
public static void close(Statement stmt) {
try {
stmt.close();
stmt.cancel();
stmt = null;
} catch (SQLException e) {
e.printStackTrace();
}
}
/**
* 关闭PreparedStatement
* @param pstmt PreparedStatement
*/
public static void close(PreparedStatement pstmt) {
try {
pstmt.close();
pstmt.cancel();
pstmt = null;
} catch (SQLException e) {
e.printStackTrace();
}
}
/**
* 关闭结果集
* @param rs 查询结果集
*/
public static void close(ResultSet rs) {
try {
rs.close();
rs = null;
} catch (SQLException e) {
e.printStackTrace();
}
}使用之后每次都会 Connection connection = DB.createConn();
PreparedStatement pstmt = DB.prepare(connection, sql);//获取stmt
ResultSet rs = null;
try {
pstmt.setString(1, XXXX);
rs = pstmt.executeQuery();
while(rs.next()){
XXXXXX
}
} catch (SQLException e) {
e.printStackTrace();
}finally{
DB.close(rs);
DB.close(pstmt);
DB.close(connection);
}
附上测试截图
这里测试数据connection都已经有了3万个,而我都是每次打开都关闭了为什么会这样,而且程序跑一会就会虚拟机溢出。各位大侠,小弟在此谢过,附上100分
很奇怪我尝试过使用常开connection连接,就是一个操作中保持一个Connection不关闭,但是PreparedStatement的数量也一直在增加,不知道为什么,还是我的程序有问题,附上代码:
数据库操作封装类:/**
* 获取数据库连接
* @return 数据库连接
*/
public static Connection createConn() {
Connection conn = null;
try {
Class.forName(DBData.DRIVER);
conn = DriverManager.getConnection(DBData.getURLForMySQL(), DBData.USER, DBData.PASSWORD);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
//JOptionPane.showMessageDialog(Source.getMainWindow(), "创建数据库连接失败,请检查服务器运行状态.");
//return createConn();
}
return conn;
}
/**
* 获取数据库Statement
* @param conn 数据库连接
* @return 数据库stmt
*/
public static Statement createStmt(Connection conn) {
Statement stmt = null;
try {
stmt = conn.createStatement();
} catch (SQLException e) {
e.printStackTrace();
}
return stmt;
}
/**
* 获取数据库PreparedStatement
* @param conn 连接
* @param sql sql语句
* @return PreparedStatement
*/
public static PreparedStatement prepare(Connection conn, String sql) {
PreparedStatement ps = null;
try {
ps = conn.prepareStatement(sql);
} catch (SQLException e) {
e.printStackTrace();
}
return ps;
}
/**
* 关闭Connection
* @param conn 数据库连接
*/
public static void close(Connection conn) {
try {
conn.close();
conn = null;
} catch (SQLException e) {
e.printStackTrace();
}
}
/**
* 关闭Statement
* @param stmt Statement
*/
public static void close(Statement stmt) {
try {
stmt.close();
stmt.cancel();
stmt = null;
} catch (SQLException e) {
e.printStackTrace();
}
}
/**
* 关闭PreparedStatement
* @param pstmt PreparedStatement
*/
public static void close(PreparedStatement pstmt) {
try {
pstmt.close();
pstmt.cancel();
pstmt = null;
} catch (SQLException e) {
e.printStackTrace();
}
}
/**
* 关闭结果集
* @param rs 查询结果集
*/
public static void close(ResultSet rs) {
try {
rs.close();
rs = null;
} catch (SQLException e) {
e.printStackTrace();
}
}使用之后每次都会 Connection connection = DB.createConn();
PreparedStatement pstmt = DB.prepare(connection, sql);//获取stmt
ResultSet rs = null;
try {
pstmt.setString(1, XXXX);
rs = pstmt.executeQuery();
while(rs.next()){
XXXXXX
}
} catch (SQLException e) {
e.printStackTrace();
}finally{
DB.close(rs);
DB.close(pstmt);
DB.close(connection);
}
附上测试截图
这里测试数据connection都已经有了3万个,而我都是每次打开都关闭了为什么会这样,而且程序跑一会就会虚拟机溢出。各位大侠,小弟在此谢过,附上100分
finally{
DB.close(rs);
DB.close(pstmt);
DB.close(connection);
}关闭了,测试工具是PTPT
public static void close(Statement stmt) {
try {
stmt.close();
stmt.cancel(); // cancel 应该放在close之前
stmt = null; // 这句话没有意义
} catch (SQLException e) {
e.printStackTrace();
}
}整个过程后台没有任何异常信息?方便把外循环完整点贴出来看看么?就是你说的死循环。
public synchronized void run() {
while(threadFlag){
control.reFresh();
//数据的更新时间为1秒更新一次
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}然后在control.reFresh();中作数据的读取和处理。其中较为频繁的数据库读取操作则采用了常开连接。对于不是很频繁的数据库操作,则打开连接后就关闭。
操作例子基本为上面的Connection connection = DB.createConn();
PreparedStatement pstmt = DB.prepare(connection, sql);//获取stmt
ResultSet rs = null;
try {
pstmt.setString(1, XXXX);
rs = pstmt.executeQuery();
while(rs.next()){
XXXXXX
}
} catch (SQLException e) {
e.printStackTrace();
}finally{
DB.close(rs);
DB.close(pstmt);
DB.close(connection);
}
Connection connection = DB.createConn();
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
pstmt = DB.prepare(connection, sql);//获取stmt
pstmt.setString(1, XXXX);
rs = pstmt.executeQuery();
while(rs.next()){
XXXXXX
}
} catch (SQLException e) {
e.printStackTrace();
}finally{
if (rs!=null) DB.close(rs);
if (pstmt!=null) DB.close(pstmt);
DB.close(connection);
}
要是里面有,并且能用,就直接用;
要是里面有,不能用,就重新放进去一个,用新的这个;
要是没有,就新放进去一个,用新的这个;当然,线程关闭的时候,释放资源。
* 线程常开连接
*/
private static Connection connection = null;/**
* 获得连接
* @return {@link Connection}
*/
private static synchronized Connection getConnection() {
if(connection == null){
connection = DB.createConn();
}
return connection;
} /**
* 清除连接
*/
public static void clearConnection() {
if(connection != null){
DB.close(connection);
connection = null;
}
}