从Session中获取Connection需要注意的

虽然不推荐从Session中获取connection,但是偶尔会出现一些特殊情况不得以这样做。

接下来的问题就是:使用后的session/connection如何处理?

[b]1.close connection[/b]
相信大多数人的第一返回会是这样,关闭连接,这是非常错误的(没来得及看官方文档,自己做了下测试)
[quote]
[b]配置(连接池中任何情况只一条连接)[/b]
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="initialSize" [color=red]value="1"[/color] />
<property name="maxActive" [color=red]value="1"[/color] />
<property name="maxIdle" [color=red]value="1"[/color] />
<property name="minIdle" [color=red]value="1"[/color] />
</bean>[/quote]

/**多线程测试关闭连接*/
public static void closeTest() throws SQLException{
Session session = Test.getSession();
Connection conn = null;
PreparedStatement pst = null;
try{
conn = session.connection();
pst = conn.prepareStatement(sql);
pst.executeQuery();
}catch(Exception e){
e.printStackTrace();
}finally{
conn.close();
pst.close();
}
}

我本来是开的4个线程分别去执行这个方法20次,结果刚到第二次的时候,连接池便抛异常:
[color=red]Timeout waiting for idle object[/color](获取连接超时)。甚至后来只开一个线程也不行。

这里很奇怪,从连接池中取出来的connection不是已经经过包装了吗?在close()的时候会自动将连接放回连接池!?
我打印conn.getClass() 得到的是一个$Proxy,父类java.lang.reflect.Proxy
而从直接连接池(BasicDataSource)中取出来的是org.apache.commons.dbcp.PoolingDataSource$PoolGuardConnectionWrapper
当然,也不能断定从session取出来的connection的close方法没有(试图)放入连接池,[color=red]但事实是它的确没有正确归还[/color]。
而开四个线程同时跑以下代码没有一点问题,这个实验有点废....
public static void poolTest() throws SQLException{
getConnection().close();
}

(我打算用javasisst把从session中取出来的connection的close方法打印出来,实在找到其它方法如看动态代理的源代码,此处待续...)

[b]2.Session.close();[/b]
将上面测试代码换成
public static void closeSessionTest() throws SQLException{
Session session = Test.getSession();
Connection conn = null;
PreparedStatement pst = null;
try{
conn = session.connection();
pst = conn.prepareStatement(sql);
pst.executeQuery();
}catch(Exception e){
e.printStackTrace();
}finally{
session.close();
if(pst != null){
pst.close();
}

}
}

ok!运行阶段没有异常。运行数速度也很快.!
分析见下一测试。

[b]3.Session.disconnect();[/b]
测试代码
public static void closeSessionTest() throws SQLException{
Session session = Test.getSession();
Connection conn = null;
PreparedStatement pst = null;
try{
conn = session.connection();
pst = conn.prepareStatement(sql);
pst.executeQuery();
}catch(Exception e){
e.printStackTrace();
}finally{
session.disconnect();
if(pst != null){
pst.close();
}

}
}

运行结果正常,速度也正常。

[b][color=red]很明显,对于从session中取出connection千万不要close()[/color][/b]
进一步看hibernate源码,session.close()与session.disconnect()中都有一个(正常)分支流程是
if ( rootSession == null ) {
return jdbcContext.getConnectionManager().close();
}

而这个方法调用的是一个cleanup()的方法,具体的源码以后补上,晚了.
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值