proxool 0.9.1-解决 Attempt to register duplicate pool 异常

今天客户发来的日志中发现异常。该异常偶尔在程序启动的时候出现。

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) {
    //省略
}






  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
proxool.xml 是一个配置文件,用于配置 Proxool 数据库连接池。Proxool 是一个开源的 Java 数据库连接池,它允许应用程序在运行时动态地管理数据库连接,以提高应用程序的性能和可靠性。 proxool.xml 文件包含以下信息: 1. 数据库驱动程序的类名和连接字符串。 2. 数据库连接池的配置信息,例如最大连接数、最小连接数、最大空闲时间等。 3. 用户名和密码等连接数据库所需的凭证信息。 proxool.xml 文件的示例代码如下: ``` <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE proxool PUBLIC "-//mikebob.net/proxool//DTD Proxool//EN" "proxool.dtd"> <proxool> <driver-url>jdbc:mysql://localhost/mydb</driver-url> <driver-class>com.mysql.jdbc.Driver</driver-class> <user>myuser</user> <password>mypassword</password> <maximum-connection-count>50</maximum-connection-count> <minimum-connection-count>10</minimum-connection-count> <simultaneous-build-throttle>20</simultaneous-build-throttle> <house-keeping-test-sql>select 1</house-keeping-test-sql> <house-keeping-sleep-time>30000</house-keeping-sleep-time> </proxool> ``` 其中,`driver-url`、`driver-class`、`user`、`password` 分别表示数据库连接字符串、数据库驱动程序的类名、用户名和密码;`maximum-connection-count`、`minimum-connection-count` 分别表示连接池的最大连接数和最小连接数;`simultaneous-build-throttle` 表示同时建立连接的最大数目;`house-keeping-test-sql` 表示定期检查连接是否可用的 SQL 语句;`house-keeping-sleep-time` 表示定期检查连接的时间间隔。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值