java.sql.Connection的close方法究竟干了啥(以MySQL为例)(二)

2015-01-21 11:16:02 · 作者: · 浏览: 28
vior of "lifecycle" methods on our connection implementation. (这个接口的实现可以通过connectionLifecycleInterceptors configuration property来安装,接收时间并且改变我们connection实现当中的lifecycle方法的行为)。这不是重点,重点是下面这个realClose。代码太长,我贴在最后。

通过阅读realClose的代码,可以发现这个方法有四个参数,前三个都是boolean类型,第四个是Throwable类型。calledExplicitly为这个方法是否是从close()方法调用的,issueRollback表示在释放资源的时候是否需要回滚操作rollback()。后两个参数没有给出注释,只好顾名思义,skipLocalTeardown表示是否跳过local teardown(在google上没有搜到什么有价值的结果……),reason最终在代码中被赋值给ConnectionImpl的forceClosedReason(Why was this connection implicitly closed, if known? (for diagnostics) 为什么这个连接是隐式关闭的,如果原因可知(诊断用))。这两个参数和我们研究的问题关系不大。realClose核心代码在此:

?

       try {
            if (!skipLocalTeardown) { // part 1 starts
                   // ......
                try {
                    closeAllOpenStatements();
                } catch (SQLException ex) {
                    sqlEx = ex;
                } // part 1 ends

                if (this.io != null) { // part 2 starts
                    try {
                        this.io.quit();
                    } catch (Exception e) {
                    }

                }
            } else {
                this.io.forceClose();
            } // part 2 ends

            if (this.statementInterceptors != null) { // part 3 starts
                for (int i = 0; i < this.statementInterceptors.size(); i++) {
                    this.statementInterceptors.get(i).destroy();
                }
            }

            if (this.exceptionInterceptor != null) {
                this.exceptionInterceptor.destroy();
            } // part 3 ends
        } finally {
            // part 4 starts
            this.openStatements = null;
            if (this.io != null) {
                this.io.releaseResources();
                this.io = null;
            }
            this.statementInterceptors = null;
            this.exceptionInterceptor = null;
            ProfilerEventHandlerFactory.removeInstance(this);

            synchronized (getConnectionMutex()) {
                if (this.cancelTimer != null) {
                    this.cancelTimer.cancel();
                }
            }

            this.isClosed = true;
            // part 4 ends
         }
     }
在代码中做了注释,

?

part 1 通过closeAllIOpenStatements方法关闭了该连接中所有处于打开状态的声明statement,

part 2 用来关闭连接的IO(通过quit或forceClose方法),

part 3 用来销毁(destroy)连接的声明拦截器(statement interceptor)和异常拦截器(exception interceptor),

part 4 将上述已经关闭的openStatements, IO (如果IO不为null,则通过releaseResources方法释放资源), statementInterceptors和exceptionInterceptor置为null,并删除掉这个连接对应的的ProfilerEventHandler(这个类在jdbc的源码里就是孤零零一个接口,没有对应注释),将连接的cancelTimer计时器取消掉,再将连接的isClosed属性设置为true(代码中看到的isClosed方法就是返回这个属性的值)。

所以,通过这些代码,我们大概可以看出MySQL JDBC在建立一个连接的时候需要申请使用什么样的资源,至于这些资源有什么用,我再研究研究,后面的文章里再接着跟大家唠。^_^

写到这里才发现自己蠢哭了T_T,如果close方法只是将Connection置为null,那么怎么调用isClosed方法呢?唉,too young too naive,写了这么半天才转过弯来。 T_T

不过通过阅读代码,发现realclose方法将释放后的资源对象的引用都置为了null,这是一个启发,以后在对connection调用完close方法之后,再将其设置为null,免得写着写着就忘了这连接已经被关闭不能使用了(因为会直接NullPointerException),也算是减少潜在的bug风险。总之,读一趟代码下来,收获还是挺大的。听周围很多外国同行说,我们国内的程序员不愿意和大家分享自己的收获和所得,听着惭愧啊。好,这边一点了都,写到这里,感谢一下中间给我递雪糕的室友,我们下篇文章再见。Cya.

附com.jdbc.mysql.ConnectionImpl.realClose方法完整源码,感兴趣大家可以一起研究,哈哈:

?

    /**
     * Closes connection and frees resources.
     * 
     * @param calledExplicitly
     *            is this being called from close()
     * @param issueRollback
     *            should a rollback() be issued?
     * @throws SQLException
     *             if an error occurs
     */
    public void realClose(boolean calledExplicitly, boolean issueRollback, boolean skipLocalTeardown, Throwable reason) throws SQLException {
        SQLException sqlEx = null;

        if (this.isClosed()) {
            return;
        }

        this.forceClosedReason = reason;

        try {
            if (!skipLocalTeardown) {
                if (!getAutoCommit() && issueRollback) {
                    try {
                        rollback();
                    } catch (SQLException ex) {
                        sqlEx = ex;
                    }
                }

                reportMetrics();

                if (getUseUsageAdvisor()) {
                    if (!calledExplicitly) {
                        String message = "Connection implicitly closed by Driver. You should call Connection.close() from your code to free resources more efficiently and avoid resource leaks.";

                        this.eventSink.consumeEvent(new Profile