做项目的时候,遇见空异常,而且不是经常的,本来想将就的放过,可考虑到偶尔影响用户的正常使用,对用户体验非常不好,还是要花些时间查找问题的根源。结果如预料的那样,跟转发来的这篇博文讲述的性质一模一样。
同时再赞叹一声,转发来的这位博主,写的很详尽。下面是原文:
今天客户发来的日志中发现异常。该异常偶尔在程序启动的时候出现。
- java.sql.SQLException: org.logicalcobwebs.proxool.ProxoolException: Attempt to register duplicate pool called 'pool'
- at org.logicalcobwebs.proxool.ProxoolDriver.connect(ProxoolDriver.java:109)
- at java.sql.DriverManager.getConnection(DriverManager.java:582)
- at java.sql.DriverManager.getConnection(DriverManager.java:185)
检查了下代码,似乎没有什么问题,一切都是按照proxool的教程中的example写的。于是把proxool的源代码下载,发现似乎真的有问题。
在类ProxoolDriver中,方法public Connection connect(String url, Properties info) 中,
- if (!ConnectionPoolManager.getInstance().isPoolExists(alias)) {
- ProxoolFacade.registerConnectionPool(url, info, false);
- cp = ConnectionPoolManager.getInstance().getConnectionPool(alias);
- }
这部分代码逻辑很简单,首先判断连接池的别名是否存在(isPoolExists),如果不存在,创建;已经存在,则直接获得连接。
在第2行的registerConnectionPool中,再次判断,该别名是否存在,如果已经存在,则抛出异常:
- if (!ConnectionPoolManager.getInstance().isPoolExists(alias)) {
- ConnectionPoolDefinition cpd = new ConnectionPoolDefinition(url, info, explicitRegister);
- registerConnectionPool(cpd);
- } else {
- throw new ProxoolException("Attempt to register duplicate pool called '" + alias + "'");
- }
那么,自然而然地考虑,这部分代码在并发的时候会出现问题。比如,下面两个thread, 分别调用getConnection
Thread1 Thread2
运行至(1), isPoolExists ? False 运行至(1), isPoolExists ? False
运行至(2), 进入registerConnectionPool 运行至 (2) registerConnectionPool是static synchronized, 被阻塞住
创建完毕,返回
此时进入registerConnectionPool
If 处判断为已经存在(因为Thread1已经创建了),进入04行的else块,在05行抛出异常
然后写一小段程序来测试下:
- import java.sql.*;
- public class TestForBug {
- public static void main(String[] arug) {
- new Thread(new T()).start();
- new Thread(new T()).start();
- }
- }
- class T implements Runnable {
- public void run() {
- Connection connection = null;
- try {
- Class.forName("org.logicalcobwebs.proxool.ProxoolDriver");
- try {
- String url = "proxool.example:com.mysql.jdbc.Driver:jdbc:mysql://192.168.1.100:3306/mr";
- String username = "root";
- String password = "password";
- connection = DriverManager.getConnection(url, username, password);
- } catch (SQLException e) {
- System.err.println("Problem getting connection" + e.toString());
- }
- if (connection != null) {
- System.out.println("Got connection :)");
- } else {
- System.err.println("Didn't get connection, which probably means that no Driver accepted the URL");
- }
- } catch (ClassNotFoundException e) {
- System.err.println("Couldn't find driver " + e.getMessage());
- } finally {
- try {
- if (connection != null) {
- connection.close();
- }
- } catch (SQLException e) {
- System.err.println("Problem closing connection " + e);
- }
- }
- }
- }
这段程序十有八九会抛出那个异常。
这就怪了。Proxool用的也很多,为啥会犯这么低级的错误呢。后来在跟踪的时候,发现:
如果运行在JDK5下,就没问题;
如果运行在JDK6下,则有问题。
查看下运行的堆栈,为:
测试代码
java.sql.DriverManager.
org.logicalcobwebs.proxool.Driver
既然测试代码和proxool.Driver都没改变,那么就看看java.sql.DriverManager是怎么回事。
结果真相大白了。
JDK5中:
- public static synchronized Connection getConnection(String url,
- String user, String password) throws SQLException {
- //省略
- }
JDK6中:
- public static Connection getConnection(String url,
- String user, String password) throws SQLException {
- //省略
- }
也就是,上面说的并发的问题,在JDK5中是同步的。因为DriverManager里面的方法就是同步的。但是在6中就不是了。这就是为啥上面的isPoolExists的代码失效的原因。也就是说,在JDK6中,proxool可能会出现这个问题。
那么解决也很简单,修改ProxoolDriver,把connect方法加上synchronized即可:
- public synchronized Connection connect(String url, Properties info) {
- //省略
- }
相关推荐
proxool-0.9.1.jar proxool_cglib-0.9.1.jar 用于连接池的配置
proxool-0.9.1.jar下载 hibernate3+ proxool-0.9.1配置说明 我刚配好,总结出来和大家分享下
包含proxool-0.9.1.jar与proxool-cglib.jar,欢迎下载
proxool配置参数说明。 spring结合proxool的datasource配置方法 及proxool-0.9.1.jar proxool-cglib.jar
修复了houseKeepingSleepTime maximumActiveTime 和 maximumConnectionLifetime 的类型long的set方法的bug
struts2.2.3+spring2.5.6+hibernate3.2+proxool0.9.1 proxool数据库连接池例子 0资源下载
proxool-0.9.1 jar;proxool-cglib.jar; 数据连接池
proxool连接池0.9.1版本的源码,可供大家修改
proxool-0.9.1.jar包是一个数据库连接池包,最新版解决前几个版本里在二次关闭一个rs集的时候警告等一些bug。proxool-0.9.1.jar监控在对中文监控出现乱码情况做了更改。具体是对org.logicalcobwebs.proxool.admin....
Proxool0.9.1的配置与应用[定义].pdf
亲测可用。 此包 包括 proxool.0.9.1.jar proxool_cgilib.0.9.1.jarg两个JAR包,主要用于需要解决连接池监控中文问题!!!
proxool-0.9.1,官网下载太慢,方便下载。
proxool-0.9.1-source源码
解决在使用spring 配置 proxool 0.9.1时碰到‘houseKeepingSleepTime’is not writeable or has an invalid setter method的问题。 方法是将org.logicalcobwebs.proxool.ProxoolDataSource 中houseKeepingSleepTime...
proxool-0.9.1.tar.gz ,java版开源连接池,短小精悍
proxool数据库连接池组建jar包 包括proxool-0.9.1.jar和commons-logging.jar两个文件