在运行时添加 JDBC jar 时没有为 HSQL db 找到合适的 JDBC 驱动程序?

Posted

技术标签:

【中文标题】在运行时添加 JDBC jar 时没有为 HSQL db 找到合适的 JDBC 驱动程序?【英文标题】:No suitable JDBC driver found for HSQL db when adding JDBC jar at run time? 【发布时间】:2018-01-04 16:18:25 【问题描述】:

我在运行时将 JDBC jar 用于 HSQL db(即:它从设置文件加载此 jar 文件的文件路径,而不是作为 Maven 依赖项进行硬修复)。但是,我无法像以前一样通过在运行时添加 JDBC jar 来获得到这个 HSQL 数据库的 SQL 连接。这是我在运行时为 HSQL DB 加载 JDBC jar 文件的代码:

Connection connection;
try 
    // this is hard fix for example, ~/hsqldb-2.3.3.jar should be gotten from a setting file
    File jdbcJarFile = new File("~/hsqldb-2.3.3.jar");          
    URL urls[] =  jdbcJarFile.toURI().toURL() ;
    URLClassLoader loader = new URLClassLoader(urls, DatabaseUtil.class.getClassLoader());
    Thread.currentThread().setContextClassLoader(loader);
    loader.loadClass("org.hsqldb.jdbcDriver");

    // no error but nothing happens
    Class.forName("org.hsqldb.jdbcDriver", true, loader); 

    // throw exception because cannot find the driver for HSQL DB
    // with this url: jdbc:hsqldb:file://home/abc/hsqldb/test        
    connection = DriverManager.getConnection(datasourceURL, datasourceUserName, datasourcePassword);
 catch(Exception ex) 
    //  (java.sql.SQLException) java.sql.SQLException: No suitable driver found for jdbc:hsqldb:file://home/abc/hsqldb/test
    throw new SQLException(ex);

我不想在编译时将此 jar 添加到类路径中,只在运行时添加。

【问题讨论】:

“我不想在编译时将这个 jar 添加到类路径中,只在运行时添加”。好的,然后将您的 pom 中的范围设置为runtime。这似乎是一种迂回的方式来做你想做的事。 @rmlan 我想从设置文件中加载这个 jar,而不是在 POM 中。 我很好奇它的价值是什么。你能解释一下你想要完成什么吗? @rmlan 它只是 JDBC jar 文件的路径,您可以在代码“~/hsqldb-2.3.3.jar”中查看示例 不,我明白了,但我不明白从设置文件加载 jar 文件名称的价值。我认为你给自己增加了不必要的困难。 【参考方案1】:

问题在于DriverManager 不允许您的类看到此驱动程序,因为您的类没有被包含 HSQLDB 驱动程序的类加载器的层次结构加载。

具体来说,DriverManager.getConnection 迭代所有驱动程序,并调用方法 isDriverAllowed,该方法最终通过调用带有驱动程序名称的 Class.forName 来检查是否可以从调用者类的类加载器加载驱动程序,并且检查它是否返回与当前驱动程序相同的类。这会失败,因为驱动程序类不在调用者类或其任何父类的类加载器中。

要使其工作,您需要使用与驱动程序相同的类加载器(或该类加载器的子类)来加载调用者类,或者您需要通过加载驱动程序来破解类加载器层次结构在系统类加载器中(这在 Java 9 中变得相当困难,如果不是不可能的话)。

这样做可能更简单:

Driver driver = (Driver) Class.forName("org.hsqldb.jdbc.JDBCDriver", true, loader).newInstance();
Properties props = new Properties();
props.setProperty("user", datasourceUserName);
props.setProperty("password", datasourcePassword);
connection = driver.connect(datasourceURL, props);

这意味着您完全跳过DriverManager。由于类加载器问题,我不确定这是否会影响你,所以我建议你仔细测试一下。

【讨论】:

我找到了一种无需使用 DriverManager 即可获得 JDBC 连接的更简单方法,无论如何感谢您的详细回答。【参考方案2】:

所以我找不到在运行时通过 DriverManager 获取 JDBC 连接的方法,但我可以使用 DataSource 来做到这一点

 // Load JDBC jar from setting file normally
 File jdbcJarFile = new File(pathToJarFile);
 URL urls[] = jdbcJarFile.toURI().toURL();
 URLClassLoader loader = new URLClassLoader(urls, Thread.currentThread().getContextClassLoader());
 Thread.currentThread().setContextClassLoader(loader);

 // Create a javax.sql DataSource object (org.springframework.boot.autoconfigure.jdbc.DataSourceBuilder)
 DataSource dataSource = DataSourceBuilder.create().url("hsqlb_url").username("sa").password("").build();

 // Get a java.sql.Connection object
 Connection connection = dataSource.getConnection();          

【讨论】:

你使用的是哪个DataSourceBuilder 我正在使用 Spring 框架(org.springframework.boot.autoconfigure.jdbc.DataSourceBuilder)

以上是关于在运行时添加 JDBC jar 时没有为 HSQL db 找到合适的 JDBC 驱动程序?的主要内容,如果未能解决你的问题,请参考以下文章

使用 jdbc:embedded-database 时如何连接到 Spring 创建的 HSQL?

Weblogic 中的 HSQL 配置

HSQL 嵌入式数据库

如何将 HSQL DB Manager 连接到嵌入式数据库

从单元测试连接时,HSQL 立即关闭连接

当库被提取到可运行的 jar 中时,JDBC 运行良好,但在它们刚刚打包时运行良好