13

この種のコードを使用して、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

2 番目のループは同じドライバーを示していますが、MySQL ドライバーはありません。

私の質問はなぜですか?私は何か見落としてますか?

ドライバーがロードされている場合、すべてのドライバーがドライバーマネージャーによって自分自身を登録しようとすることの JavaDocDriverManagerを読みました。私のコードでは、これはloader.loadClass(drivername);. たとえば、このコードは静的部分を呼び出す必要があると思いました。

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

クラスDriver。_

4

2 に答える 2

20

これは、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");
于 2013-01-23T12:23:22.577 に答える
7

DriverManager呼び出し元のコードがアクセスできないドライバー (つまり、別のクラスローダーによってロードされたドライバー) を使用できないため、この方法では実行できません。

メソッドgetConnectionが呼び出されると、 は、初期化時にロードされたドライバと、現在のアプレットまたはアプリケーションと同じクラスローダを使用して明示的にDriverManagerロードされたドライバの中から適切なドライバを見つけようとします。

私の知る限り、唯一の可能な回避策はDriver、使用する代わりに手動でインスタンス化することですDriverManager(引数なしのコンストラクターがあると仮定します):

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

それが正しいアプローチかどうかはわかりませんが。

于 2013-01-23T11:53:42.420 に答える