java c/s模式线程JDBC问题
最近在做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); }
另外,为了安全,考虑应把 pstmt 放到 try 之内,类似:
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);
}
[解决办法]
表面上看,没啥问题。楼主把所有关闭里面的cancel方法去了试试。
当然,我倒是有个想法,可以绕开这个问题。
既然是定时有个线程来巡检,不妨把数据库连接,放到TheadLocal里面,每次从这里面取。
要是里面有,并且能用,就直接用;
要是里面有,不能用,就重新放进去一个,用新的这个;
要是没有,就新放进去一个,用新的这个;
当然,线程关闭的时候,释放资源。
[解决办法]
先把方法中所有cancel(); 放在close()前试试