当前位置: 代码迷 >> GIS >> proxool 0.9.1,解决 Attempt to register duplicate pool 错误(转)
  详细解决方案

proxool 0.9.1,解决 Attempt to register duplicate pool 错误(转)

热度:568   发布时间:2016-05-05 06:06:44.0
proxool 0.9.1,解决 Attempt to register duplicate pool 异常(转)

做项目的时候,遇见空异常,而且不是经常的,本来想将就的放过,可考虑到偶尔影响用户的正常使用,对用户体验非常不好,还是要花些时间查找问题的根源。结果如预料的那样,跟转发来的这篇博文讲述的性质一模一样。

?

同时再赞叹一声,转发来的这位博主,写的很详尽。下面是原文:

?

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

?

[java]?view plaincopy
  1. java.sql.SQLException:?org.logicalcobwebs.proxool.ProxoolException:?Attempt?to?register?duplicate?pool?called?'pool'??
  2. ????at?org.logicalcobwebs.proxool.ProxoolDriver.connect(ProxoolDriver.java:109)??
  3. ????at?java.sql.DriverManager.getConnection(DriverManager.java:582)??
  4. ????at?java.sql.DriverManager.getConnection(DriverManager.java:185)??


检查了下代码,似乎没有什么问题,一切都是按照proxool的教程中的example写的。于是把proxool的源代码下载,发现似乎真的有问题。

?

在类ProxoolDriver中,方法public Connection connect(String url, Properties info) 中,

?

[java]?view plaincopy
  1. if?(!ConnectionPoolManager.getInstance().isPoolExists(alias))?{??
  2. ?????ProxoolFacade.registerConnectionPool(url,?info,?false);?????
  3. ?????cp?=?ConnectionPoolManager.getInstance().getConnectionPool(alias);??
  4. }???

?

这部分代码逻辑很简单,首先判断连接池的别名是否存在(isPoolExists),如果不存在,创建;已经存在,则直接获得连接。

在第2行的registerConnectionPool中,再次判断,该别名是否存在,如果已经存在,则抛出异常:

?

[java]?view plaincopy
  1. if?(!ConnectionPoolManager.getInstance().isPoolExists(alias))?{??
  2. ?????ConnectionPoolDefinition?cpd?=?new?ConnectionPoolDefinition(url,?info,?explicitRegister);??
  3. ?????registerConnectionPool(cpd);??
  4. }?else?{??
  5. ?????throw?new?ProxoolException("Attempt?to?register?duplicate?pool?called?'"?+?alias?+?"'");??
  6. }??

?

那么,自然而然地考虑,这部分代码在并发的时候会出现问题。比如,下面两个thread, 分别调用getConnection

? ? ? Thread1 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?Thread2

运行至(1), isPoolExists ? False ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 运行至(1), isPoolExists ? False

运行至(2), 进入registerConnectionPool ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?运行至?(2) registerConnectionPool是static synchronized, 被阻塞住

创建完毕,返回 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?此时进入registerConnectionPool

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?If 处判断为已经存在(因为Thread1已经创建了),进入04行的else块,在05行抛出异常

然后写一小段程序来测试下:

?

[java]?view plaincopy
  1. import?java.sql.*;??
  2. ??
  3. public?class?TestForBug?{??
  4. ????public?static?void?main(String[]?arug)?{??
  5. ????????new?Thread(new?T()).start();??
  6. ????????new?Thread(new?T()).start();??
  7. ????}??
  8. }??
  9. ??
  10. class?T?implements?Runnable?{??
  11. ??
  12. ????public?void?run()?{??
  13. ????????Connection?connection?=?null;??
  14. ????????try?{??
  15. ????????????Class.forName("org.logicalcobwebs.proxool.ProxoolDriver");??
  16. ????????????try?{??
  17. ????????????????String?url?=?"proxool.example:com.mysql.jdbc.Driver:jdbc:mysql://192.168.1.100:3306/mr";??
  18. ????????????????String?username?=?"root";??
  19. ????????????????String?password?=?"password";??
  20. ????????????????connection?=?DriverManager.getConnection(url,?username,?password);??
  21. ????????????}?catch?(SQLException?e)?{??
  22. ????????????????System.err.println("Problem?getting?connection"?+?e.toString());??
  23. ????????????}??
  24. ????????????if?(connection?!=?null)?{??
  25. ????????????????System.out.println("Got?connection?:)");??
  26. ????????????}?else?{??
  27. ????????????????System.err.println("Didn't?get?connection,?which?probably?means?that?no?Driver?accepted?the?URL");??
  28. ????????????}??
  29. ????????}?catch?(ClassNotFoundException?e)?{??
  30. ????????????System.err.println("Couldn't?find?driver?"?+?e.getMessage());??
  31. ????????}?finally?{??
  32. ????????????try?{??
  33. ????????????????if?(connection?!=?null)?{??
  34. ????????????????????connection.close();??
  35. ????????????????}??
  36. ????????????}?catch?(SQLException?e)?{??
  37. ????????????????System.err.println("Problem?closing?connection?"?+?e);??
  38. ????????????}??
  39. ????????}??
  40. ????}??
  41. }??

这段程序十有八九会抛出那个异常。

这就怪了。Proxool用的也很多,为啥会犯这么低级的错误呢。后来在跟踪的时候,发现:

如果运行在JDK5下,就没问题;

如果运行在JDK6下,则有问题。

查看下运行的堆栈,为:

测试代码

java.sql.DriverManager.

org.logicalcobwebs.proxool.Driver

既然测试代码和proxool.Driver都没改变,那么就看看java.sql.DriverManager是怎么回事。

结果真相大白了。

JDK5中:

[java]?view plaincopy
  1. public?static?synchronized?Connection?getConnection(String?url,???
  2. ????String?user,?String?password)?throws?SQLException?{????
  3. ????????//省略??
  4. }??

JDK6中:

[java]?view plaincopy
  1. public?static?Connection?getConnection(String?url,???
  2. ????String?user,?String?password)?throws?SQLException?{????
  3. ????????//省略??
  4. }??

?

也就是,上面说的并发的问题,在JDK5中是同步的。因为DriverManager里面的方法就是同步的。但是在6中就不是了。这就是为啥上面的isPoolExists的代码失效的原因。也就是说,在JDK6中,proxool可能会出现这个问题。

那么解决也很简单,修改ProxoolDriver,把connect方法加上synchronized即可:

?

[java]?view plaincopy
  1. public?synchronized?Connection?connect(String?url,?Properties?info)?{??
  2. ????//省略??
  3. }??

?

?

?

?

原文链接:http://blog.csdn.net/lff0305/article/details/8277983

  相关解决方案