Java:jdbc:h2找不到合适的驱动程序

13

我的代码出了问题,我已经搜索并尝试了我知道的一切,但没有任何运气。


情境:

  • 应用程序检查是否存在JDBC驱动程序,这里是H2驱动程序(org.h2.Driver)。
  • 如果不存在,则应用程序会下载JDBC驱动程序,并像以下方式一样将其添加到ClassLoader中:注意:storageDataManager是我用于SQL方法的一个类)

       File h2Driver = new File(directory.toString() + File.separator + "lib" + File.separator + "h2.jar");
       if (h2Driver.exists()) {
           URL[] url = new URL[0];
           try {
               url = new URL[]{h2Driver.toURI().toURL()};
               storageDataManager.setClassLoader(new URLClassLoader(url));
           } catch (MalformedURLException ignore) {}
        }
    

当storageDataManager运行第一个查询时,它尝试连接指定的驱动程序,如果它有一个类加载器,则使用类加载器代替:

if (getClassLoader() != null) {
    getLogging().debug("Loading custom class loader for H2 driver: " + getClassLoader().toString());
    Driver driver = (Driver) Class.forName("org.h2.Driver", true, getClassLoader()).newInstance();
    getLogging().debug("Loaded H2 driver: " + driver.toString() + " - " + driver.getMinorVersion() + " - " + driver.getMajorVersion());
    DriverManager.registerDriver(driver);
} else {
    getLogging().debug("Loading H2 driver.");
    Class.forName("org.h2.Driver");
}
outputDrivers();
this.con = DriverManager.getConnection(this.url, this.username, this.password);
break;

当我运行应用程序时,出现以下错误:

"*No suitable driver found for jdbc:h2:plugins\Odin\data\OdinStorage;AUTO_RECONNECT=TRUE*"

这是完整日志:

[Debug] Loading custom class loader for H2 driver: java.net.URLClassLoader@3bf3d5f4
[Debug] Loaded H2 driver: org.h2.Driver@67257ce8 - 3 - 1
[Debug] Checking DriverManager drivers.
[Debug] Found driver #1: sun.jdbc.odbc.JdbcOdbcDriver
[Debug] Found driver #2: com.mysql.jdbc.Driver
[Debug] Found 2 drivers in DriverManager.
--------------------------- STACKTRACE ERROR ---------------------------
Class name: java.sql.DriverManager
Error message: No suitable driver found for jdbc:h2:plugins\Odin\data\OdinStorage;AUTO_RECONNECT=TRUE
Error cause: null
File name: null
Function name: getConnection
Error line: -1
--------------------------- STACKTRACE START ---------------------------
java.sql.DriverManager.getConnection(Unknown Source)
java.sql.DriverManager.getConnection(Unknown Source)
com.craftfire.commons.managers.DataManager.connect(DataManager.java:756)
com.craftfire.commons.managers.DataManager.executeQuery(DataManager.java:526)
com.craftfire.odin.managers.StorageManager.checkInventoryDatabase(StorageManager.java:65)
com.craftfire.odin.managers.StorageManager.checkDatabases(StorageManager.java:56)
com.craftfire.odin.managers.StorageManager.<init>(StorageManager.java:34)
com.craftfire.odin.managers.OdinManager.loadDatabases(OdinManager.java:206)
com.craftfire.odin.managers.OdinManager.init(OdinManager.java:75)
com.craftfire.odin.layer.bukkit.Odin.onEnable(Odin.java:63)
org.bukkit.plugin.java.JavaPlugin.setEnabled(JavaPlugin.java:217)
org.bukkit.plugin.java.JavaPluginLoader.enablePlugin(JavaPluginLoader.java:374)
org.bukkit.plugin.SimplePluginManager.enablePlugin(SimplePluginManager.java:381)
org.bukkit.craftbukkit.CraftServer.loadPlugin(CraftServer.java:266)
org.bukkit.craftbukkit.CraftServer.enablePlugins(CraftServer.java:248)
org.bukkit.craftbukkit.CraftServer.<init>(CraftServer.java:200)
net.minecraft.server.ServerConfigurationManagerAbstract.<init>(ServerConfigurationManagerAbstract.java:50)
net.minecraft.server.ServerConfigurationManager.<init>(SourceFile:11)
net.minecraft.server.DedicatedServer.init(DedicatedServer.java:105)
net.minecraft.server.MinecraftServer.run(MinecraftServer.java:377)
net.minecraft.server.ThreadServerApplication.run(SourceFile:539)
---------------------------- STACKTRACE END ----------------------------
我的问题是:为什么驱动程序不会显示在DriverManager.getDrivers()中?
注意:我不想将库添加到CLASSPATH,这就是为什么我需要找到解决上述问题的方法的原因。
那么我该如何解决这个问题呢?我只需要从jar文件中加载H2 JDB驱动程序。
我也尝试过以下方法:
- 不使用DriverManager.registerDriver(Driver),而是使用Class.forName("org.h2.Driver", true, getClassLoader()),同时也尝试使用.newInstance(),但两者都没有起作用。
能否有人给我提供一个解决方案呢?
谢谢!

H2的JAR文件是否在你的类路径中? - Code-Apprentice
我不想将驱动程序添加到我的类路径中,这就是为什么我要下载jar文件并尝试加载它,这就是我需要解决的问题。 - Contex
为什么你不想将它添加到类路径中? - Miserable Variable
你需要将JAR文件添加到类路径中。这并不一定意味着要更改全局CLASSPATH环境变量。还有其他几种方法可以实现。 - Code-Apprentice
8个回答

5
根据Oracle文档:http://docs.oracle.com/cd/E19501-01/819-3659/beadf/index.html 类加载器将类加载委托给子类加载器,在类路径上搜索类。但是,您用于加载库的URLClassloader对系统或引导层次结构不可见,因此它无法找到该类(尽管已加载,尽管在另一个castl...classloader中)。
最简单的解决方法是使用URLClassloader替换系统类加载器,并使用addUrl(...path...)来加载您的库,正如这个答案所建议的:How should I load Jars dynamically at runtime?

2
作为附注,即使使用“外部”类加载器注册的驱动程序也无济于事,因为每当请求驱动程序(例如创建连接时),驱动程序管理器都会检查这一点。请参阅DriverManager中的'isDriverAllowed(Driver driver,ClassLoader classLoader)'方法(我在JDK7_u7中进行了检查)。因此,您不能在不同的类加载器层次结构之间共享JDBC驱动程序。使用@Afforess提出的解决方案将解决该问题。 - Pyranja
就我个人而言,我认为这个答案是错误的。我不同意认为有必要费这么大劲。只需将JAR放入CLASSPATH中,然后继续进行。 - duffymo
@duffymo - 有些情况下,您可能不想将库融入您的项目中,或者使用替代jdbc连接器。仅因为看不到用例并不意味着没有任何用例。 - Afforess
但是你正在使用H2的JDBC连接器,你别无选择。这个解决方案并没有解决任何问题。你只是通过使用与系统不同的类加载器增加了复杂性。除了“我说了算”之外,你还没有描述任何用例。 - duffymo

3
我遇到了同样的问题。在pom.xml中配置了h2驱动程序:

<dependency>
    <groupId>com.h2database</groupId>
    <artifactId>h2</artifactId>
    <version>1.4.193</version>
</dependency>

因为我的项目中使用的是Java 6(不要问我为什么),但是从Maven仓库获取的h2-1.4.193.jar依赖于Java 7,所以无法使用该驱动程序版本。
将pom.xml更改为使用h2-1.4.190.jar解决了我的问题。
另请参见h2database git项目中的问题#300

1
在我的情况下,错误出现在Maven范围中。
    <dependency>
        <groupId>com.h2database</groupId>
        <artifactId>h2</artifactId>
        <version>1.4.200</version>
        <scope>test</scope>
    </dependency>

当你将其移除或更改为可见范围后,它就可以工作了。

1

Hibernate属性设置url值为:

jdbc:h2:mem:test;DB_CLOSE_DELAY=-1

driverClassName:

<property name="driverClassName">
<value>org.hibernate.dialect.H2Dialect</value>

在pom文件中添加H2驱动程序:
    <dependency>
        <groupId>com.h2database</groupId>
        <artifactId>h2</artifactId>
        <version>1.3.166</version>
    </dependency>

1

您必须将 确切的 org.h2.Driver *.jar 文件名称添加到应用程序的类路径中。

例如: /home/applications/games/minecraft/drivers/jdbcH2driver.jar

因此,决定驱动程序将始终在应用程序中的位置,并找到应用程序主文件夹路径以在安装使用它的应用程序时完全构建它。

此外,它可能无法运行,因为在从网络下载时可能需要时间,并且必须将其复制到“应用程序类路径的正确文件夹”中才能使用,并使用正确的 .jar 名称(如上段所述)。 为了成功下载,“查询和应用程序操作应该放在一个线程中”,以防止超出下一条指令的范围。

明智的做法是,在应用程序启动时检查 .jar 是否存在,如果不存在,则下载它并向用户发出警告,提示用户下载它。


0

我在我的Kotlin项目中遇到了同样的问题。

我已经在bild.gradle.kts中添加了

dependencies {
    implementation("com.h2database:h2:1.4.199")
..
}

然后在IntelliJ中选择“文件”->“无效缓存”。

0

我在使用groovygrapes进行依赖项解析时遇到了这个错误。

解决方案:

您需要告诉grapes使用systemClassLoader,例如:

@GrabConfig(systemClassLoader=true)

0

2
我不想将H2 jar添加到我的类路径中,这就是为什么我选择下载它,但是加载已下载的jar文件并没有起作用,这就是我正在寻找解决方案的原因。 - Contex
你没有选择,我也不明白为什么你不想将H2 JAR添加到你的CLASSPATH中。这是Java的工作方式。 - duffymo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接