虽然不推荐从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]
我本来是开的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]。
而开四个线程同时跑以下代码没有一点问题,这个实验有点废....
(我打算用javasisst把从session中取出来的connection的close方法打印出来,实在找到其它方法如看动态代理的源代码,此处待续...)
[b]2.Session.close();[/b]
将上面测试代码换成
ok!运行阶段没有异常。运行数速度也很快.!
分析见下一测试。
[b]3.Session.disconnect();[/b]
测试代码
运行结果正常,速度也正常。
[b][color=red]很明显,对于从session中取出connection千万不要close()[/color][/b]
进一步看hibernate源码,session.close()与session.disconnect()中都有一个(正常)分支流程是
而这个方法调用的是一个cleanup()的方法,具体的源码以后补上,晚了.
接下来的问题就是:使用后的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()的方法,具体的源码以后补上,晚了.