Hibernate之默认连接池

这个问题的主要思考主要源自于测试系统的一个问题,应用运行几个小时之后,就报出了数据库连接关闭问题。起初分析一段最近改动过的代码如下:

Connection conn = null;
ConnectionProvider cp = null;

try{
cp = 获取连接池类,这里代码因***原因,不能写出来,望见谅
conn = cp.getConnection();
.....
}finally{
cp.closeConnection(conn);
}

起初根据这段代码。分析是否连接池中的连接都已经关闭,那么从连接池中获取的关闭连接,就无法使用了,这只是猜想,代码和微测试是检验真理的唯一标准(还有一种方式就是找大神),进行Hibernate连接池源码分析。

1、hibernate可以使用C3P0这种第三方提供的连接池,当然不进行配置的话,Hibernate也会默认提供一个连接池:DriverManagerConnectionProvider

//连接池,为一个arrayList
private final ArrayList pool;
//连接池大小
private int poolSize;

//构造函数,创建ArrayList对象
public DriverManagerConnectionProvider()
  {
    this.pool = new ArrayList();

    this.checkedOut = 0;
  }

//获取连接方法
public Connection getConnection()
    throws SQLException
  {
    if (log.isTraceEnabled()) log.trace("total checked-out connections: " + this.checkedOut);

    //从连接池获取连接,哇,这里居然用到了同步,每次获取连接池中的数据库连接都要加锁,看来Hibernate默认数据库连接不适合高并发场景。还有Hibernate真实连接大小可以超过默认poolSize
    synchronized (this.pool) {
//连接池不为空,则从连接池中获取
      if (!(this.pool.isEmpty())) {
        int last = this.pool.size() - 1;
        if (log.isTraceEnabled()) {
          log.trace("using pooled JDBC connection, pool size: " + last);
          this.checkedOut += 1;
        }
        Connection pooled = (Connection)this.pool.remove(last);
        if (this.isolation != null) pooled.setTransactionIsolation(this.isolation.intValue());
        if (pooled.getAutoCommit() != this.autocommit) pooled.setAutoCommit(this.autocommit);
        return pooled;
      }
    }
   
   //连接池为空,则创建新的连接并返回
    log.debug("opening new JDBC connection");
    Connection conn = DriverManager.getConnection(this.url, this.connectionProps);
    if (this.isolation != null) conn.setTransactionIsolation(this.isolation.intValue());
    if (conn.getAutoCommit() != this.autocommit) conn.setAutoCommit(this.autocommit);

    if (log.isDebugEnabled()) {
      log.debug("created connection to: " + this.url + ", Isolation Level: " + conn.getTransactionIsolation());
    }
    if (log.isTraceEnabled()) this.checkedOut += 1;

    return conn;
  }

  //哈哈,这里就是closeConnection方法,可以看到,当前连接池大小如果小于poolSize(poolSize默认20),则会把该连接放入池中,否则,关闭连接
  public void closeConnection(Connection conn) throws SQLException
  {
    if (log.isDebugEnabled()) this.checkedOut -= 1;

    synchronized (this.pool) {
      int currentSize = this.pool.size();
      if (currentSize < this.poolSize) {
        if (log.isTraceEnabled()) log.trace("returning connection to pool, pool size: " + (currentSize + 1));
        this.pool.add(conn);
        return;
      }
    }

    log.debug("closing JDBC connection");

    conn.close();
  }

 经过分析,可以得出

1、closeConnection方法,只有当当前连接池大小如果小于poolSize(poolSize默认20),则会把该连接放入池中,否则,关闭连接。所以,猜想关闭的连接放入连接池中是错误的。
2、连接池的获取连接和关闭连接,都需要对连接池(pool)加锁,则默认连接池大小不适合高并发场景。
3、Hibernate真实连接大小可以超过默认poolSize。

相关推荐