其实,自己写,好像也没有很好的办法。
各个jdbc driver对连接无效给出的异常没有标准。往往就是一个SQLException。让你很难区分这是一个普通的数据库异常还是因为数据库重新启动了或者fail over了。而且,也不存在一个安全的测试异常状态的函数。isClosed()不能用,因为它只表示这个connection.close()是否被调用过。
各个jdbc driver对连接无效给出的异常没有标准。往往就是一个SQLException。让你很难区分这是一个普通的数据库异常还是因为数据库重新启动了或者fail over了。而且,也不存在一个安全的测试异常状态的函数。isClosed()不能用,因为它只表示这个connection.close()是否被调用过。
public Connection getConnection() throws SQLException
{
while(没有超时)
{
Connection conn = 取得一个空闲的连接
try
{
用conn执行一下数据库操作(如执行一条简单的SELECT语句)
return conn; //成功,返回该连接
}
catch(SQLException e)
{
丢弃conn
e.printStackTrace();
}
}
throw new SQLException("取连接超时");
}虽然速度慢了一点,但可以在一定程度上解决数据库重启的问题
有些错误可以认为无法恢复(如网络失败或者硬盘耗尽),但是有些错,比如类型匹配错,资源申请暂时超时等应该可以恢复的。
cbhyk() ,你的代码里面的“用conn执行一下数据库操作”就是随便执行一下测试语句?
这样,不是就引入了一个来回roundtrip?感觉很不舒服,而且也有违与连接池的高效率的目的。而且,如果遇到fail over的情况,不希望简简单单地抱错,最理想的情况是,连接池可以发现问题,自动关闭放弃当前的连接,并且重新产生新的连接。所有这一切应该透明于用户,甚至最好对应用程序透明。据我想,一个可能的方案是,连接池内部纪录一个当前的池版本id,并且把这个id赋给每一个生成的Connection对象。
一旦发生SQLException,连接池就进入一个特殊的“清理”状态。这个状态内部,把当前的版本id加一,把正在cache的连接全部关掉。遇到连接返回池的时候,检查版本id,如果不同于新的版本id,就关掉它而不是缓存。
但是,这个方法的一个问题是:如果万一某一个连接发生了任何一个上述的SQLException,那么就意味着整个池进入这个“清理”状态。
而连接池必须封装所有的ResultSet, Statement,Connection等 jdbc对象,一个对象也不能直接漏给程序员。这些封装的ResultSet proxy, Statement proxy, Connection proxy等需要重载所有的方法,截取所有的异常。而且这些异常里面也许有其它的合法异常,不分青红皂白地遇到SQLException就关闭Connection好象也不是很好。
但是,这个东西做起来好象比较复杂,而且,似乎也没有连接池这么做。
这个系统本来目标是24/7,看来做不到了。
解决办法竟然这么简单,使用c3p0,一个开源的pool,自带连接恢复功能。
最后采用了jakarta的commons-DBCP才得以解决他们的解决方法是,定一个Query语句作为测试用
一旦数据库发生错误,就测试Connection是否连通
如果连不通则抛弃重新建立Conn很简单的:〉
谢谢。我下载了c3p0,看了一下它的代码。似乎,它也是在给用户返回一个connection的时候(当然,它也有idle时候的检查)检查这个连接的状态,通过的方法就是检查一个预先创建好的表是否还在。
也一样是一个roundtrip的检查了(看来这必不可少)它还通过检查SQLException里面的error code,它认为state code 08001, 08001代表数据库无效,需要重新启动连接池。
truezerg,看来不浪费时间来保证连接有效是不可能的了。只能说,做这个测试的时间,远远小于创建连接本身的时间。
另外,连接的有效性必须在连接被返回给用户之前做,返回给用户后,再试图处理恢复就很复杂了。好在,database fail over这种东西,可以允许某些用户的连接失败,只要新用户的连接能够成功,就好了。