Mybatis源码解析之——数据源池化技术(三)

一.介绍

  随着上一章讲述了有池化技术的数据源中的获得连接方法(popConnection)。我们这一节接着讲其他核心方法以及数据源工厂。

二.分析

1.回收链接方法(pushConnection)

流程

1.从活跃列表移除这个链接

2.判断是这个链接是否合法有效,如果有效,判断空闲链接数是否太少,太少就新建一个链接,然后把这个链接放入到空闲链接中,再通知别的线程可以使用这个新链接。如果太多,就直接将这个链接关闭即可。

3如果链接不合法,池中失败链接计数加一

代码

protected void pushConnection(PooledConnection conn) throws SQLException {
        //加锁
        synchronized(this.state) {
        //先从活跃队列中删除这个链接
            this.state.activeConnections.remove(conn);
            
        //判断连接是否合法
            if (conn.isValid()) {
                //连接合法
                PoolState var10000;
                
                //判断空闲队列目前是否小于最小空闲连接数
                if (this.state.idleConnections.size() < this.poolMaximumIdleConnections && conn.getConnectionTypeCode() == this.expectedConnectionTypeCode) {
                       //如果小于,
                    var10000 = this.state;
                    var10000.accumulatedCheckoutTime += conn.getCheckoutTime();
                     //回滚 保证数据一致性
                    if (!conn.getRealConnection().getAutoCommit()) {
                        conn.getRealConnection().rollback();
                    }
                    
                    //通过这个连接对象来创建新的空闲连接
                    PooledConnection newConn = new PooledConnection(conn.getRealConnection(), this);
                           //加入到空闲队列
                    this.state.idleConnections.add(newConn);
                    //更新这个新的连接的创建时间
                    newConn.setCreatedTimestamp(conn.getCreatedTimestamp());
                   //更新这个新的连接的最近使用时间
                    newConn.setLastUsedTimestamp(conn.getLastUsedTimestamp());
                    conn.invalidate();
                    if (log.isDebugEnabled()) {
                        log.debug("Returned connection " + newConn.getRealHashCode() + " to pool.");
                    }

                    //唤醒 让别的线程可以使用它 
                    this.state.notifyAll();
                } else {


                    //如果不小于,证明空闲队列中还是有新的连接
                    var10000 = this.state;
                    var10000.accumulatedCheckoutTime += conn.getCheckoutTime();
                    if (!conn.getRealConnection().getAutoCommit()) {
                        conn.getRealConnection().rollback();
                    }
                      //关b连接
                    conn.getRealConnection().close();
                    if (log.isDebugEnabled()) {
                        log.debug("Closed connection " + conn.getRealHashCode() + ".");
                    }

                    conn.invalidate();
                }
            } else {
                //如果这个要删除的连接不合法,就计数失败链接+1
                if (log.isDebugEnabled()) {
                    log.debug("A bad connection (" + conn.getRealHashCode() + ") attempted to return to the pool, discarding connection.");
                }

                ++this.state.badConnectionCount;
            }

        }
    }

2.强制关闭所有连接(forceCloseAll)

流程

1.关闭所有的活跃连接

2.关闭所有的空闲连接

public void forceCloseAll() {
        synchronized(this.state) {
//根据url、username、password获得预连接类型码(也不是很重要,个人感觉就是标识用)
            this.expectedConnectionTypeCode = this.assembleConnectionTypeCode(this.dataSource.getUrl(), this.dataSource.getUsername(), this.dataSource.getPassword());

            int i;
            PooledConnection conn;
            Connection realConn;
               //依次关闭所有的活跃连接
            for(i = this.state.activeConnections.size(); i > 0; --i) {
                try {
                    conn = (PooledConnection)this.state.activeConnections.remove(i - 1);
                    conn.invalidate();
                    realConn = conn.getRealConnection();
                    //没自动提交,进行回滚
                    if (!realConn.getAutoCommit()) {
                        realConn.rollback();
                    }

                    realConn.close();
                } catch (Exception var7) {
                }
            }

                 //依次关闭所有的空闲连接
            for(i = this.state.idleConnections.size(); i > 0; --i) {
                try {
                    conn = (PooledConnection)this.state.idleConnections.remove(i - 1);
                    conn.invalidate();
                    realConn = conn.getRealConnection();
                    if (!realConn.getAutoCommit()) {
                        realConn.rollback();
                    }

                    realConn.close();
                } catch (Exception var6) {
                }
            }
        }

        if (log.isDebugEnabled()) {
            log.debug("PooledDataSource forcefully closed/removed all connections.");
        }

    }

3.其他辅助方法

这里我主要讲一下关于属性注入的方

法,其他属性方法(获得连接等)读者自行阅读,比较简单好理解。

本质:其实有池化的数据源属性注入方法本质就是调用无池化数据源的属性注入方法

代码

 public void setDriver(String driver) {
        this.dataSource.setDriver(driver);
        this.forceCloseAll();
    }

    public void setUrl(String url) {
        this.dataSource.setUrl(url);
        this.forceCloseAll();
    }

    public void setUsername(String username) {
        this.dataSource.setUsername(username);
        this.forceCloseAll();
    }

    public void setPassword(String password) {
        this.dataSource.setPassword(password);
        this.forceCloseAll();
    }

省略的部分不是偷懒!哈哈,是因为如果篇幅太长,读者容易看不下去,我觉得文章精短是最好的,再说你都到这部分看懂啦,其他的就很轻松

三.数据源工厂

其实本质就是继承了无池化工厂,实现无池化工厂那一套

public class PooledDataSourceFactory extends UnpooledDataSourceFactory {
    public PooledDataSourceFactory() {
        this.dataSource = new PooledDataSource();
    }
}

其实你很容易看出来这个设计的巧妙,无池化数据源和有池化数据源本质上就是内部实现不同,然后通过工厂设置一些固定属性(url、driver等)。这样不同数据源的工厂就可以共用一套生成数据源的代码。不同的数据源工厂只需要在构造器中引入自己对应的数据源即可。

四.总结

到这里,mybatis源码的池化技术到这里就完事啦,如果你把这三章的内容完全理解啦,那恭喜你对这一部分有所进步。

--关注我,持续输出高质量文章

  • 6
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值