[JDBC]你真的会正确关闭connection吗?
Connection conn = null;
PreparedStatement stmt = null;
ResultSet rs = null;
try {
conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1/test","root","fendou");
stmt = conn.prepareStatement("select 1 from dual");
rs = stmt.executeQuery();
while(rs.next()){
System.out.println("OK");
}
} catch (SQLException e) {
e.printStackTrace();
}finally{
try {
if(rs != null){
rs.close();
}
if(stmt != null){
stmt.close();
}
if(conn != null){
conn.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
上面是一段很常见的jdbc代码.通常,我们都是在finally里释放资源,经常可以看到有人或者为了美观,或者为了省事,将rs.close(),stmt.close(),conn.close()放到同一个try,catch块中.事实上,这样子关闭是不够严谨是.如果rs.close()或者stmt.close()执行的时候抛出了异常,那么就不会执行conn.close(),也就没法正确关闭connection了.
为了保证connection可以正常关闭,我们稍微调整一下代码.如下:
finally{
try {
if(rs != null){
rs.close();
}
} catch (SQLException e) {
//handle the exception
}
try{
if(stmt != null){
stmt.close();
}
}catch(SQLException e){
//handle the exception
}
try{
if(conn!= null){
conn.close();
}
}catch(SQLException e){
//handle the exception
}
这样即使出了异常,也可以保证代码向下执行.这种情况下,通常我们会在catch块中通常忽略掉异常,不去做处理,或者做简单的打印一下,但是不能将异常转化成运行时异常抛出。因为一旦在catch块中抛出异常,程序就无法向下执行了。
当然,最正确的写法应该是这样:
try {
if(rs != null){
rs.close();
}
}catch(SQLException e){
// do something
} finally{
try{
if(stmt != null){
stmt.close();
}
}catch(Exception e){
// do something
}finally{
if(conn != null){
try {
conn.close();
} catch (SQLException e) {
// do something
}
}
}
}
这样的写法虽然正确,但是看起来十分的丑陋,于是采取了一个折中的办法.在方法上声明throws SQLException,方法体中这样关闭,代码相对简洁一些.
try {
if(rs != null){
rs.close();//(1)
}
} finally{
try{
if(stmt != null){
stmt.close();//(2)
}
}finally{
if(conn != null){
conn.close();//(3)
}
}
}
这时候我会有这样一个疑问,如果(1)(2)(3)处都抛出了异常,那么方法会抛出哪儿个异常.事实证明,最后产生是异常会被抛出.前面的两个异常会被丢弃掉.
一般我会定义两个方法来专门处理关闭,根据不能的需求,一个会抛出SQLException,一个会忽略掉异常(ignore).相对来说,这样的代码最简洁,省去了重复的try,catch.
// close(conn,stmt,rs)
// close(conn,stmt,null)
// close(conn,null,null)
public static void close(Connection conn, PreparedStatement stmt,
ResultSet rs) throws SQLException {
try {
if(rs != null){
rs.close();
}
} finally{
try{
if(stmt != null){
stmt.close();
}
}finally{
if(conn != null){
conn.close();
}
}
}
} public static void closeQuietly(Connection conn, PreparedStatement stmt,
ResultSet rs){
try{
close(conn, stmt,rs);
}catch(SQLException e){
//quietly
}
}
很多人在关闭的时候喜欢这么写:
//略去stmt和rs
connection.close();
connection = null;
这里讨论下connection = null这句是否有必要.有人说connection =null有助于垃圾回收.
个人认为connection = null是没有必要的.
从原理上来说,connection对象的回收,与它的状态是否是isClosed没有关系,而是取决于这个对象是否被引用.换句话说,即使connection没有close,也是可以被回收的.close()方法的作用是通知数据库端及时的释放资源.
经过下面程序的验证,即使不写connection=null,connection也可以很好的被垃圾回收.没有看出connection=null对垃圾回收有什么积极的影响;
另外从打印结果来看,垃圾收集是并行的.
package me.qiu.jdbc; import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException; public class CloseDemo { public static void main(String[] args){
try {
Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
for (int i = 0; i < 100; i++) {
jdbc();
}
} private static void jdbc() {
MyConnection conn = null;
PreparedStatement stmt = null;
ResultSet rs = null;
int b = 0;
try {
conn = new MyConnection(DriverManager.getConnection("jdbc:mysql://127.0.0.1/test","root","fendou"));
stmt = conn.prepareStatement("select 1 from dual");
rs = stmt.executeQuery();
while(rs.next()){
b = rs.getInt(1);
System.out.println(b);
}
} catch (SQLException e) {
e.printStackTrace();
}finally{
closeQuietly(conn, stmt, rs);
}
} // close(conn,stmt,rs)
// close(conn,stmt,null)
// close(conn,null,null)
public static void close(MyConnection conn, PreparedStatement stmt,
ResultSet rs) throws SQLException {
try {
if(rs != null){
rs.close();
rs = null;
}
} finally{
try{
if(stmt != null){
stmt.close();
stmt = null;
}
}finally{
if(conn != null){
conn.close();
// conn = null;
}
}
}
} public static void closeQuietly(MyConnection conn, PreparedStatement stmt,
ResultSet rs){
try{
close(conn, stmt,rs);
}catch(SQLException e){
//quietly
}
}
} class MyConnection{
Connection conn;
MyConnection(Connection conn){
this.conn = conn;
} public PreparedStatement prepareStatement(String sql) throws SQLException {
return conn.prepareStatement(sql);
} public void close() throws SQLException{
conn.close();
} @Override
protected void finalize() throws Throwable {
System.out.println("gc ...");
}
}
[JDBC]你真的会正确关闭connection吗?的更多相关文章
- 解决com.microsoft.sqlserver.jdbc.SQLServerException: 该连接已关闭
com.microsoft.sqlserver.jdbc.SQLServerException: 该连接已关闭. at com.microsoft.sqlserver.jdbc.SQLServerEx ...
- golang 网络编程之如何正确关闭tcp连接以及管理它的生命周期
欢迎访问我的个人网站获取更佳阅读排版 golang 网络编程之如何正确关闭tcp连接以及管理它的生命周期 | yoko blog (https://pengrl.com/p/47401/) 本篇文章部 ...
- mybatis 如何关闭connection
1.前言 最开始操作数据库是使用jdbc操作数据库,每次创建一个连接都需要关闭连接,避免占用资源.比如 Class.forName("com.jdbc.mysql.Driver") ...
- 要恢复页面吗?Chrome未正确关闭
谷歌chrome浏览器每次打开提示"要恢复页面吗"怎么办? 谷歌chrome浏览器每次打开提示"要恢复页面吗"怎么办? 如下图所示: 每次打开启动谷歌chrom ...
- eclipse上一次没有正确关闭,导致启动的时候卡死错误解决方法
关于 eclipse启动卡死的问题(eclipse上一次没有正确关闭,导致启动的时候卡死错误解决方法),自己常用的解决方法: 方案一(推荐使用,如果没有这个文件,就使用方案二): 到<works ...
- 线程池ExecutorService的使用及其正确关闭方法
创建一个容量为5的线程池 ExecutorService executorService = Executors.newFixedThreadPool(5); 向线程池提交15个任务,其实就是通过线程 ...
- [翻译][Java]ExecutorService的正确关闭方法
https://blog.csdn.net/zaozi/article/details/38854561 https://blog.csdn.net/z69183787/article/details ...
- spring boot 服务 正确关闭方式
引言 Spring Boot,作为Spring框架对“约定优先于配置(Convention Over Configuration)”理念的最佳实践的产物,它能帮助我们很快捷的创建出独立运行.产品级别的 ...
- java-文件流正确关闭资源
用文件流来拷贝一个文件,用到文件字节输入流(FileInputStream)和文件字节输出流(FileOutputStream),用输入流把字节文件读到缓冲数组中,然后将缓冲数组中的字节写到文件中,就 ...
随机推荐
- 洗礼灵魂,修炼python(15)--列表进阶话题—>列表解析/列表生成器
是的,我是想到什么知识点就说什么,没有固定的主题,我的标题都是在写完博客再给的.本篇博文说说列表进阶话题.其实列表应该是比较熟悉的了,而毫不夸张的说,在实际的开发中,列表也是使用的最多的,以后你会体会 ...
- Sender IP字段为"0.0.0.0"的ARP请求报文
今天在研究免费ARP的过程中,抓到了一种Sender IP字段为“0.0.0.0”的ARP请求报文(广播),抓包截图如下: 这让我很疑惑.一个正常的ARP请求不应该只是Target MAC字段为全0吗 ...
- 字符串相似度算法-LEVENSHTEIN DISTANCE算法
Levenshtein Distance 算法,又叫 Edit Distance 算法,是指两个字符串之间,由一个转成另一个所需的最少编辑操作次数.许可的编辑操作包括将一个字符替换成另一个字符,插入一 ...
- 阿里云搭建JAVA WEB环境(SQL Server + TomCat + 配置域名)
假期刚刚搭完,先写个提纲,今晚写完: 1.申请一个月的免费的云服务器ECS; 2.在云服务器上安装Java开发环境+Sql Server+Tomcat; 3.购买域名并认证,绑定服务器共有IP地址; ...
- lvm管理卷之缩减卷大小
最近刚刚装好了一个系统,但是因为没有分好区,导致home分区过大,所以想把home分区的一大半移动到根分区里面. 1.先说一下我的环境. 安装的是centos6版本的系统,使用的默认文件系统是ext4 ...
- Windows系统安装nginx及配置
1.下载nginx http://nginx.org/en/download.html 下载稳定版本,以nginx/Windows-1.12.2为例,直接下载 nginx-1.12.2 ...
- kafka集群管理工具kafka-manager部署安装
一.kafka-manager 简介 为了简化开发者和服务工程师维护Kafka集群的工作,yahoo构建了一个叫做Kafka管理器的基于Web工具,叫做 Kafka Manager.这个管理工具可以很 ...
- MySQL基本简单操作03
MySQL基本简单操作 现在我创建了一个数据表,表的内容如下: mysql> select * from gubeiqing_table; +----------+-----+ | name | ...
- JDK动态代理源码解析
动态代理.静态代理优缺点 关于JDK的动态代理,最为人熟知的可能要数Spring AOP的实现,默认情况下,Spring AOP的实现对于接口来说就是使用的JDK的动态代理来实现的,而对于类的 ...
- 如何根据name和value选中radio [问题点数:40分,结帖人zzxap
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <he ...