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. css文本属性用法总结

    稍稍总结了下css文本的一些属性用法,自己忘记的时候也可以用来查查,不用去查网站那么麻烦. 下面是部分总结,也希望对其他人有用 文本修饰 (1)text-decoration:  文本修饰(横线) 4 ...

  2. Socks5 RFC1928协议中文版

    除了这个意译版rfc1928外,其他人写的好像也有错误,都是一知半解. ☆ RFC 1928意译版(非直译版) http://www.ietf.org/rfc/rfc1928.txt http://w ...

  3. 洗礼灵魂,修炼python(51)--爬虫篇—变色龙般的伪装

    变色龙原理 变色龙这种动物想必大家都了解,它们会根据周遭环境的局势来改变自己的颜色,伪装自己. 那么爬虫有这种技能吗?当然是有的,先不着急说这个问题. 从上一篇开始,你有没有想过,站在网站管理的角度, ...

  4. python 序列化pickle 和 encode的区别

    我们把变量从内存中变成可存储或传输的过程称之为序列化. 序列化之后,就可以把序列化后的内容写入磁盘,或者通过网络传输到别的机器上. 反过来,把变量内容从序列化的对象重新读到内存里称之为反序列化,即un ...

  5. [Compression] Hadoop 压缩

    0. 说明 Hadoop 压缩介绍 && 压缩格式总结 && 压缩编解码器测试 1. 介绍 [文件压缩的好处] 文件压缩的好处如下: 减少存储文件所需要的磁盘空间 加速 ...

  6. 无需软件windows如何加密文件夹

    在百部百科上看到,放在博客中以便查看. 1.首先打开记事本,当然如果你的电脑里装有类似notepad++的文本编辑软件的也可以,但是不能用word.用这类软件好处是代码高亮,看上去舒服,减少错误率. ...

  7. python基础 - 变量与运算符

    变量与运算符 变量 定义一个变量 a = [1,2,3,4,5,6] print(a) # [1,2,3,4,5,6] 变量命名要求: 首字母不能是数字 只能包含字符数字下划线 不能是关键字 type ...

  8. <20190104>关掉一些鸡肋的Win10功能

    讨厌鬼001 # - windows defender -    本身没什么卵用, 却一直占着位置, 而且不断提示更新. 必须关闭它 . 在"运行" 中,  输入 "gp ...

  9. Django之权限管理

    Django权限管理之初步完整版 项目背景:这是一个权限管理系统(给一些角色和他们的权限指URL和页面可以删除的按钮比如:增删改查) 使用到了中间件,和初始化权限,使用了admin的后台管理系统. 我 ...

  10. 【Java多线程】AtomicLong和LongAdder

    AtomicLong简要介绍 AtomicLong是作用是对长整形进行原子操作,显而易见,在java1.8中新加入了一个新的原子类LongAdder,该类也可以保证Long类型操作的原子性,相对于At ...