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吗?的更多相关文章

  1. 解决com.microsoft.sqlserver.jdbc.SQLServerException: 该连接已关闭

    com.microsoft.sqlserver.jdbc.SQLServerException: 该连接已关闭. at com.microsoft.sqlserver.jdbc.SQLServerEx ...

  2. golang 网络编程之如何正确关闭tcp连接以及管理它的生命周期

    欢迎访问我的个人网站获取更佳阅读排版 golang 网络编程之如何正确关闭tcp连接以及管理它的生命周期 | yoko blog (https://pengrl.com/p/47401/) 本篇文章部 ...

  3. mybatis 如何关闭connection

    1.前言 最开始操作数据库是使用jdbc操作数据库,每次创建一个连接都需要关闭连接,避免占用资源.比如 Class.forName("com.jdbc.mysql.Driver") ...

  4. 要恢复页面吗?Chrome未正确关闭

    谷歌chrome浏览器每次打开提示"要恢复页面吗"怎么办? 谷歌chrome浏览器每次打开提示"要恢复页面吗"怎么办? 如下图所示: 每次打开启动谷歌chrom ...

  5. eclipse上一次没有正确关闭,导致启动的时候卡死错误解决方法

    关于 eclipse启动卡死的问题(eclipse上一次没有正确关闭,导致启动的时候卡死错误解决方法),自己常用的解决方法: 方案一(推荐使用,如果没有这个文件,就使用方案二): 到<works ...

  6. 线程池ExecutorService的使用及其正确关闭方法

    创建一个容量为5的线程池 ExecutorService executorService = Executors.newFixedThreadPool(5); 向线程池提交15个任务,其实就是通过线程 ...

  7. [翻译][Java]ExecutorService的正确关闭方法

    https://blog.csdn.net/zaozi/article/details/38854561 https://blog.csdn.net/z69183787/article/details ...

  8. spring boot 服务 正确关闭方式

    引言 Spring Boot,作为Spring框架对“约定优先于配置(Convention Over Configuration)”理念的最佳实践的产物,它能帮助我们很快捷的创建出独立运行.产品级别的 ...

  9. java-文件流正确关闭资源

    用文件流来拷贝一个文件,用到文件字节输入流(FileInputStream)和文件字节输出流(FileOutputStream),用输入流把字节文件读到缓冲数组中,然后将缓冲数组中的字节写到文件中,就 ...

随机推荐

  1. wap2app(三)-- 添加引导页

    1.在client_index.html文件中添加如下代码: <script type="text/javascript"> if(window.plus){ plus ...

  2. (网页)the server responded with a status of 403 (Forbidden)

    403跨域问题.看一下要访问的url.

  3. recovery log直接输出到串口

    我们在调试recovery升级的时候,我们经常需要查看recovery的log,google的原始逻辑中,recovery的log并非直接输出到串口,我们需要输入命令才能获取,我们有三种方式: 第一种 ...

  4. 数据库的IO and 数据库优化问题

    一.IO介绍 IO有四种类型:连续读,随机读,随机写和连续写,连续读写的IO size通常比较大(128KB-1MB),主要衡量吞吐量,而随机读写的IO size比较小(小于8KB),主要衡量IOPS ...

  5. mac上Android环境变量配置

    1.AndroidSDK路径查看 (1)AndroidStudio: 菜单栏AndroidStudio > Preferences > Appearences&Behavior & ...

  6. 根据id来大量删除数据between

    id的范围来删除数据 比如要删除 110到220的id信息:delete id from 表名 where id between 110 and 220;

  7. 比较分析C++、Java、Python、R语言的面向对象特征,这些特征如何实现的?有什么相同点?

    一门课的课后题答案,在这里备份一下: 面向对象程序设计语言 –  比较分析C++.Java.Python.R语言的面向对象特征,这些特征如何实现的?有什么相同点? C++ 语言的面向对象特征: 对象模 ...

  8. 4.1Python数据类型(1)之数值类型

    返回总目录 目录: 1.数据类型的表现形式: 2.数据进制的转换: 3.数据的常规操作: (一).数据类型的表现形式: (1)整数类型: # 二进制: a = 0b0110 print("二 ...

  9. Sql Server 只有MDF文件恢复数据库的方法以及2008清除日志文件

    首先建立同名的空数据库,然后停止数据库服务运行,将MDF文件覆盖后启动服务,并修改和执行下面的语句. alter database JinMa_NYGL set EMERGENCY alter dat ...

  10. Linux 小知识翻译 - 「Linux之父 Linus」

    作为新年的第一次,这次想简单介绍下Linus这个人.(这篇文章是作者新年初写的,所以有这么句话) Linux之父,同时也是现在linux内核开发最终决定的人物就是「Linus Torvalds」.「L ...