连接池如何做保活性检测(BeeCP)

原创
04/29 23:53
阅读数 1.5W

前段时间有网友发来信息问:您的连接池怎么没有保活性检测呢?  其实小蜜蜂连接池不但有,而且还技高一筹呢,我们的检测方式是获取到连接后的第一时间进行存活性检测的,如果检测无效,则会主动从池中移除该连接,并尝试获取下一个连接,再检测,一直取到有效的连接或超时退出;第一时间的检测在一定程度保证了池的性能方面的优势【比如国际大牌某池的做法: 从队列获到一个连接后,退出borrow方法,检测结果发现连接无效,则会再次进入borrow方法,我相信有一定的功底朋友能对比看出孰优孰劣(我希望我的代码不仅仅体现出卓越的性能,更重的要体现出严谨性,优雅性)】小蜜蜂池的思想很精炼,代码方式不搞弯弯绕绕:除非我超时,否则我必须拿到有效的连接。话题有点扯远了,继续回到我们的中心话题。

一:连接存活性检测方式

熟悉连接池的朋友,都知道连接池一般都有连接存活性检测手段,常见的方式有

A: Connection.IsValid方法(JDK1.6以后)

B: 利用Statement执行一段SQL语句(Java1.5之前)

一般性连接池都支持上述两种方式,若驱动不支持第一种方式时,连接池会按第二种方式:间隔一段时间的方式执行某段SQL语句,若无异常则判定为有效连接,所以给连接池提供测试性脚本是非常有必要的(保底性方式),测试代码的大体如下:

public boolean isAlive(Connection con,String sql){
   Statement st=null;
   try{
       st =con.createStatement();
       st.execute(sql);
       return true;
    }catch(Exception e){
      return false;
    }finally{
      if(st!=null)try{st.close();}catch(Exception e){}
    }
}

二:SQL与事务回滚

看过上述代码的朋友,也许会有下面疑问

A:这个SQL使用什么样的语句好呢?

回答:通常是一条简单性的查询语句,有的池默认语句:SELECT 1 或 SELECT 1 FROM DUAL

B:这条语句能是一条insert语句或update语句吗?

 回答:当然可以,有的池没有限定这条语句到底写成啥样。

C: 如果是一条insert语句,连接池长时间运行后,肯定会反复执行这条SQL,那么某表不会膨胀很大?

 回答:是的,如果不加上某些控制,长时间运作某表是有可能造成膨胀现象,这是一个很好的问题。

针对问题C, 我个人的观点是加入事务控制,避免来 ‘真’的(实际性改变),那么上述代码就需要调整为:

public boolean isAlive(Connection con,String sql){
   Statement st=null;
   boolean changed=false;

   try{
       if(con.getAutoCommit()){
          con.setAutoCommit(false);
          changed=true;
       }

       st =con.createStatement();
       st.execute(sql);
       return true;
    }catch(Exception e){
      return false;
    }finally{
      con.rollback();//回滚操作,必须放在finally中
      if(st!=null)try{st.close();}catch(Exception e){}
      if(changed) con.setAutoCommit(true);
    }
}

看了上述代码的朋友也许会提出: rollback为啥要写在finally中呢,直接跟在 execute方法后面不好吗?

我的回答:失败未必没有写入数据,finally是最佳位置处,我们来设想假如用户配置如下一条SQL:

select xxx() from dual

熟悉Oracle的朋友对这样的写法不陌生吧,利用一条SQL语句去执行一个存储过程,在这个基础上,我们把问题继续往前推进一步:假如这个过程中执行了100条insert语句,当执行完99条之后,最后一条insert失败了又或者全部成功呢.  亲爱的朋友们请告诉我,这种情况下是否需要回滚呢? 答案是肯定的,除非你想往库里加点料。

三: 事务切换性问题(追加点料

setAutoCommit朋友都知道这个是用于事务方面的方法,但是您知道:这个方法不能随便切换吗?随意切换会有什么后果?我的代码(https://github.com/Chris2018998/BeeCP/blob/master/src/main/java/cn/beecp/pool/ProxyConnectionBase.java)的83行代码:在 setAutoCommit方法中有一个脏标记检查异常,也许您会很好奇,为啥这样做呢? 我的回答是:数据保护的严谨性,在这种情况下,要么回滚,要么提交,否则不允许改变。下面我们做一个测试,请看下面步骤图(Oracle11g)

第一步:查看数据某表记录(空表)

第二步:编写测试代码(AutoComit 从false切换到true, 中间不回滚)

第三步:查看表结果(切换后的结果,被保存进库了)

(这个测试主要提醒大家,连接上的赃操作,不小心的话,后续的commit或关闭时,会保存存进库里)

 

最后祝社区的朋友们五一节快乐!并推荐两个开源作品 

1(连接池):https://github.com/Chris2018998/BeeCP

2(对象池):https://github.com/Chris2018998/BeeOP

展开阅读全文
打赏
3
8 收藏
分享
加载中
打赏
2 评论
8 收藏
3
分享
返回顶部
顶部