我正在尝试使用这种代码动态加载JDBC驱动程序:
try{
URL[] url={new URL("file:libs/mysql-connector-java-5.1.21.jar")};
URLClassLoader loader = new URLClassLoader(url, System.class.getClassLoader());
loader.loadClass(drivername);
Enumeration<Driver> drivers = DriverManager.getDrivers();
while(drivers.hasMoreElements()){
Driver driver = drivers.nextElement();
System.out.println("driver:"+driver);
}
Class.forName(drivername, true, loader);
drivers = DriverManager.getDrivers();
while(drivers.hasMoreElements()){
Driver driver = drivers.nextElement();
System.out.println("driver:"+driver);
}
Connection connect = DriverManager.getConnection(jdbcurl, user,
password);
return connect;
}
catch (MalformedURLException e){
e.printStackTrace();
return null;
}
第一个while循环显示类路径的驱动程序:
driver:sun.jdbc.odbc.JdbcOdbcDriver@35712651
driver:oracle.jdbc.OracleDriver@58df0438
driver:com.ibm.db2.jcc.DB2Driver@525c7734
driver:SQLServerDriver:1
并且第二个循环显示相同的驱动程序,但没有MySQL驱动程序。
我的问题是为什么?我错过了什么吗?
我读了in the JavaDoc of DriverManager
,如果驱动程序被加载,每个驱动程序都会尝试通过drivermanager注册自己。在我的代码中,这应该是loader.loadClass(drivername);
。我认为这段代码应该调用静态部分,例如:
static {
try {
java.sql.DriverManager.registerDriver(new Driver());
} catch (SQLException E) {
throw new RuntimeException("Can't register driver!");
}
}
the Driver
class的。
答案 0 :(得分:16)
这是DriverManager和类加载器的已知问题,请参阅:
http://www.kfu.com/~nsayer/Java/dyn-jdbc.html
驱动程序定义(基本上是委托):
class DriverShim implements Driver {
private Driver driver;
DriverShim(Driver d) { this.driver = d; }
public boolean acceptsURL(String u) throws SQLException {
return this.driver.acceptsURL(u);
}
public Connection connect(String u, Properties p) throws SQLException {
return this.driver.connect(u, p);
}
// and so on....
使用示例:
URL u = new URL("jar:file:/path/to/pgjdbc2.jar!/");
String classname = "org.postgresql.Driver";
URLClassLoader ucl = new URLClassLoader(new URL[] { u });
Driver d = (Driver)Class.forName(classname, true, ucl).newInstance();
DriverManager.registerDriver(new DriverShim(d));
DriverManager.getConnection("jdbc:postgresql://host/db", "user", "pw");
答案 1 :(得分:5)
你不能这样做,因为DriverManager
不允许你使用调用代码无法访问的驱动程序(即不同类加载器加载的驱动程序):
当调用方法
getConnection
时,DriverManager
将尝试从初始化时加载的那些驱动程序中找到合适的驱动程序,并使用与当前applet或应用程序相同的类加载器显式加载 强>
据我所知,唯一可行的解决方法是手动实例化Driver
而不是使用DriverManager
(假设它有一个无参数构造函数):
Driver driver = Class.forName(drivername, true, loader).newInstance();
Connection connect = driver.connect(url, props);
虽然我不确定这是一种正确的方法。