java 动态加载JDBC驱动

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/14478870/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-31 16:25:33  来源:igfitidea点击:

Dynamically load the JDBC driver

javajdbcclassloader

提问by bkb

I'm trying to load the JDBC driver dynamically with this kind of code:

我正在尝试使用这种代码动态加载 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;
    }

The first while-loop shows the drivers of the classpath:

第一个 while 循环显示了类路径的驱动程序:

driver:sun.jdbc.odbc.JdbcOdbcDriver@35712651
driver:oracle.jdbc.OracleDriver@58df0438
driver:com.ibm.db2.jcc.DB2Driver@525c7734
driver:SQLServerDriver:1

and the second loop shows the same drivers, but without the MySQL driver.

第二个循环显示相同的驱动程序,但没有 MySQL 驱动程序。

My Question is why? Did I miss something?

我的问题是为什么?我错过了什么?

I read in the JavaDoc of DriverManagerthat every driver tries to register himself by the drivermanager, if the driver is loaded. In my Code this should be loader.loadClass(drivername);. I thought this code should invoke the static part for example:

在 JavaDoc 中DriverManager读到,如果加载了驱动程序,每个驱动程序都会尝试通过 drivermanager 注册自己。在我的代码中,这应该是loader.loadClass(drivername);. 我认为这段代码应该调用静态部分,例如:

static {
  try {
      java.sql.DriverManager.registerDriver(new Driver());
  } catch (SQLException E) {
      throw new RuntimeException("Can't register driver!");
  }
}

of the Driverclass.

Driver

回答by Riccardo Cossu

that's a known issue with DriverManager and classloaders, see:

这是 DriverManager 和类加载器的一个已知问题,请参阅:

http://www.kfu.com/~nsayer/Java/dyn-jdbc.html

http://www.kfu.com/~nsayer/Java/dyn-jdbc.html

Driver definition (basically a delegate):

驱动程序定义(基本上是一个委托):

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....

Use example:

使用示例:

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");

回答by axtavt

You cannot do it this way, because DriverManagerdoesn't allow you to use drivers that the calling code doesn't have access to (i.e. drivers loaded by different classloader):

您不能这样做,因为DriverManager不允许您使用调用代码无权访问的驱动程序(即由不同的类加载器加载的驱动程序):

When the method getConnectionis called, the DriverManagerwill attempt to locate a suitable driver from amongst those loaded at initialization and those loaded explicitly using the same classloader as the current applet or application.

getConnection调用该方法时,DriverManager将尝试从初始化时加载的驱动程序和使用与当前小程序或应用程序相同的类加载器显式加载的驱动程序中找到合适的驱动程序

As far as I know the only possible workaround is to instantiate Drivermanually instead of using DriverManager(assuming that it has a no-arg constructor):

据我所知,唯一可能的解决方法是Driver手动实例化而不是使用DriverManager(假设它有一个无参数构造函数):

Driver driver = Class.forName(drivername, true, loader).newInstance();
Connection connect = driver.connect(url, props);

Though I'm not sure that it's a correct approach.

虽然我不确定这是一种正确的方法。