session 与 在其中打开的connection的关闭关系

本文探讨了一个在使用Hibernate时遇到的问题,即在只关闭Session而未关闭Connection的情况下,数据库连接可能会耗尽。通过分析Hibernate源代码,作者发现Session的close方法确实会关闭由其打开的Connection,调用jdbcContext.getConnectionManager().close(),进一步关闭底层的JDBC Connection。在SessionImpl类的connection()方法中,连接是从连接池中借用的,当调用close时,会释放回连接池。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

        前段时间做的一个应用hibernate的项目,在进行压力测试的时候发现,程序运行一段时间数据库连接就会爆满。检查程序,发现一个可疑代码,那就是使用session 打开一个connection,使用完毕之后,调用只关闭了session,但是没有关闭connection。代码如下:

在执行完业务逻辑之后,没有对打开的connection进行关闭就退出了(session的关闭在模板类RollbackTrans中完成)。现在的疑问是,只关闭session,即调用session.close()会一起关闭connection吗?带着这个疑问,我查看了源代码,写代码实际运行测试,下面是解决疑问的过程:

1、查看源代码:

session.close代码部分,代码是在org.hibernate.impl.SessionImpl中实现的

这个close做了几个事情:

1、检查是否已经关闭

2、检查是否打开统计配置,如果是的话就进行关闭统计(hibernate中有一个配置项,用于监控sessionFactory的连接情况hibernate.generate_statistics)

3、关闭所有子session

4、这点关键,与本文章讨论的问题关系很大。那就是调用jdbcContext.getConnectionManager().close()。从这行代码来看,我的猜测是:session.close应该是会关闭有它打开(session.connection())的connection。接下来我们来研究这个close方法(jdbcContext.getConnectionManager().close),看下面代码

 留意上面有中文注释的代码行,由此,我们不难断定,在调用session.close的时候,hibernate会将由本session打开的connection关闭。现在,我们来解决上面第13行代码注释的疑问,以确保上面讨论中关闭的connection对象就是由session.connection()打开的。解决这个疑问,先来看看session.connection()代码,同样,这部分代码也是在org.hibernate.impl.SessionImpl中实现的

以上jdbcContextconnectionManager和前面讨论close时的jdbcContextconnectionManager分别是同一个对象。在borrowConnection

1、  首先校验connection是否已经closed,如果是则抛出connection manager has been closed异常

2、  检查是否已经在当前session中提供了connection,如果是,则直接返回connection对象

,否则调用代理返回connection对象。再看代理类BorrowedConnectionProxy,这个类含有一个connectionManager的成员变量,查看其实现InvocationHandler 接口方法invoke的代码

 

从以上方法可以看出,当我们调用session.connection时,其实调用的就是ConnectionManager的一个实例(这个实例就是Session的一个成员变量)的方法:

public Connection getConnection() throws HibernateException {
  if ( isClosed ) {
   throw new HibernateException( "connection manager has been closed" );
  }
  if ( connection == null  ) {
   openConnection();
  }
  return connection;
 }

也就是一下方法(留意注释)

/**
  * Pysically opens a JDBC Connection.
  *
  * @throws HibernateException
  */
 private void openConnection() throws HibernateException {
  if ( connection != null ) {
   return;
  }

  log.debug("opening JDBC connection");
  try {
      //从连接池中获取连接,并设置为成员变量(这个变量就是先前close的那个了)

   connection = factory.getConnectionProvider().getConnection();


  }
  catch (SQLException sqle) {
   throw JDBCExceptionHelper.convert(
     factory.getSQLExceptionConverter(),
     sqle,
     "Cannot open connection"
    );
  }

  callback.connectionOpened(); // register synch; stats.connect()
 }

 

 

 

 

 

 

 

 

 

 

 

 

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值