[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),用输入流把字节文件读到缓冲数组中,然后将缓冲数组中的字节写到文件中,就 ...
随机推荐
- 3.网络编程-tcp的服务器简单实现
#!/usr/bin/env python # -*- coding: utf-8 -*- # @Time : 2019/1/13 22:03 # @Author : ChenAdong # @ema ...
- [20180608]Wrong Results with IOT, Added Column and Secondary Index.txt
[20180608]Wrong Results with IOT, Added Column and Secondary Index.txt --//链接:http://db-oriented.com ...
- [20170824]11G备库启用DRCP连接.txt
[20170824]11G备库启用DRCP连接.txt --//参考链接:http://blog.itpub.net/267265/viewspace-2099397/blogs.oracle.com ...
- 浅谈sql server聚集索引与非聚集索引
今天同事的服务程序在执行批量插入数据操作时,会超时失败,代码debug了几遍一点问题都没有,SQL单条插入也可以正常录入数据,调试了一上午还是很迷茫,场面一度很尴尬,最后还是发现了问题的根本,原来是另 ...
- Tell Me About Yourself Example 1
Tell Me About Yourself Employers ask this question because they want to know you have the relevant e ...
- [HDFS_4] HDFS 的 Java 应用开发
0. 说明 在 IDEA下 进行 HDFS 的 Java 应用开发 通过编写代码实现对 HDFS 的增删改查操作 1. 流程 1.1 在项目下新建 Moudle 略 1.2 为 Moudle 添加 M ...
- tkinter学习系列之(六)Radiobutton控件
目录 目录 前言 (一)基本属性 (二)在Frame里布局: 目录 前言 Radiobutton单选框,在一组选框中,只能选中一个. (一)基本属性 (1)特有属性: value 按钮的值 varia ...
- January 16th, 2018 Week 03rd Tuesday
Accept who you are, and revel in it. 接受真实的自己并乐在其中. Try to accept youself and try to love yourself mo ...
- deepin安装Oracle jdk8,以及添加add-apt-repository命令支持
@font-face{ font-family:"Times New Roman"; } @font-face{ font-family:"宋体"; } p.M ...
- 17秋 软件工程 第六次作业 Beta冲刺 总结博客
题目:团队作业--Beta冲刺 17秋 软件工程 第六次作业 Beta冲刺 总结博客 Beta冲刺过程中各个成员的贡献百分比 世强:15.5% 陈翔:14.5% 树民:12.0% 媛媛:14.0% 港 ...