groovy:捕获:java.sql.SQLException:即使使用@GrabConfig(systemClassLoader = true)也找不到合适的驱动程序

Posted

技术标签:

【中文标题】groovy:捕获:java.sql.SQLException:即使使用@GrabConfig(systemClassLoader = true)也找不到合适的驱动程序【英文标题】:groovy: Caught: java.sql.SQLException: No suitable driver found even if use @GrabConfig(systemClassLoader=true) 【发布时间】:2021-11-09 02:43:18 【问题描述】:

我有这个连接到 SQL Server 的测试代码:

@GrabConfig(systemClassLoader=true)
@Grab(group='com.microsoft.sqlserver', module='mssql-jdbc', version='9.2.1.jre8')
import groovy.sql.Sql

def server = '10.6.6.1'
def port = '1433'
def user = 'sa'
def password = 'somepassword'

def url = "jdbc:sqlserver://$server:$port;databaseName=master;"

Sql.withInstance(url, user, password)  sql ->

    def serverName = sql.firstRow('SELECT @@SERVERNAME')

    assert serverName[0]


如果我运行它,我会得到:

捕获:java.sql.SQLException:找不到适合 jdbc:sqlserver://10.6.6.1:1433;databaseName=master; 的驱动程序 java.sql.SQLException:找不到适合 jdbc 的驱动程序:sqlserver://10.6.6.1:1433;databaseName=master; 在 test.run(test.groovy:12)

驱动程序的 jar 肯定是由 Grape 下载的,因为我可以在我的主目录的 .groovy/ 目录的子目录中找到它。

但是我无法连接到服务器。

我使用的是 groovy 3.0.9,但我尝试使用旧版本,结果是一样的。

编辑:

如果我在连接前添加代码:

Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver")

它有效,但很奇怪,我确信这不再需要了。 如果有人能解释一下。

【问题讨论】:

【参考方案1】:

还是需要在java.sql.DriverManager注册sql驱动

每个 jdbc 驱动程序通常在 XyzDriver 类中包含大约以下代码:

static 
    try 
        java.sql.DriverManager.registerDriver( new XyzDriver() )
     catch (SQLException e) 
        ...
    

同样适用于 microsoft sql 驱动程序:https://github.com/microsoft/mssql-jdbc/blob/09d35bfc2338f1fc7c41a958d1e627fa0d6a2b65/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDriver.java#L732

这就是为什么你必须调用像Class.forName("XyzDriver")这样的代码来让驱动程序在DriverManager中自我注册


UPD:JDBC 4.0 / java8+

来自 javadoc:https://docs.oracle.com/javase/8/docs/api/java/sql/DriverManager.html

JDBC 4.0 驱动程序必须包含文件META-INF/services/java.sql.Driver ...

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

mssql-jdbc-9.2.1.jre8.jar 与 4.0 兼容。它在META-INF/services/java.sql.Driver 文件中包含com.microsoft.sqlserver.jdbc.SQLServerDriver

不过,让我们检查一下 DriverManager 代码以及它如何查找驱动程序:

http://hg.openjdk.java.net/jdk8/jdk8/jdk/file/tip/src/share/classes/java/sql/DriverManager.java#l100

static 
    loadInitialDrivers();
    println("JDBC DriverManager initialized");

DriverManager 在加载时尝试查找驱动程序。因此,jdbc 驱动程序必须在应用启动时出现在类路径中才能自动注册。

@Grab 在代码中并非如此。

作为抓取后的解决方法,您可以这样做来为所有驱动程序调用自我注册:

ServiceLoader.load(java.sql.Driver.class).iterator().findAll()

【讨论】:

从我在这里读到的“自动加载 JDBC 驱动程序”docs.oracle.com/javadb/10.8.3.0/ref/rrefjdbc4_0summary.html 如果驱动程序是 jdbc 4.x 驱动程序,则不再需要 Class.forName(driver)。这与apache derby有关,但重点是jdbc 4.x驱动程序版本。 关于您上次的编辑,当您说“jdbc 驱动程序必须存在于应用程序启动时的类路径中。而@Grab 在代码中的情况并非如此。”我在想这与GrabConfig(systemClassLoader = true) 有关所以这不是这个设置的目的? systemClassLoader 的目的 - 使用系统类加载器(而不是 groovy 类加载器)。但这不是关于何时执行此操作。没有systemClassLoaderDriverManager 甚至看不到下载的驱动程序工件。

以上是关于groovy:捕获:java.sql.SQLException:即使使用@GrabConfig(systemClassLoader = true)也找不到合适的驱动程序的主要内容,如果未能解决你的问题,请参考以下文章

如何捕获传递给 Groovy 脚本的参数?

替换groovy中的捕获组

groovy:捕获:java.sql.SQLException:即使使用@GrabConfig(systemClassLoader = true)也找不到合适的驱动程序

Value '0000-00-00' can not be represented as java.sql.Date解决办法

Groovy 配置环境变量

07-Groovy-异常处理