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

groovy: Caught: java.sql.SQLException: No suitable driver found even if use @GrabConfig(systemClassLoader=true)

我有这个测试代码可以连接到 SQL 服务器:

@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]

}

如果我 运行 我得到:

Caught: java.sql.SQLException: No suitable driver found for jdbc:sqlserver://10.6.6.1:1433;databaseName=master; java.sql.SQLException: No suitable driver found for jdbc:sqlserver://10.6.6.1:1433;databaseName=master; at test.run(test.groovy:12)

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

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

我正在使用 groovy 3.0.9,但我尝试使用旧版本,它是一样的。

编辑:

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

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

它可以工作,但是很奇怪,我确信这不再是必需的了。 如果有人能解释一下。

它仍然需要在 java.sql.DriverManager

中注册 sql 驱动程序

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

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

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

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

中自行注册

更新: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 将尝试从初始化加载的驱动程序和使用与当前小程序或应用程序相同的 class加载程序显式加载的驱动程序中找到合适的驱动程序。

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 驱动程序必须在应用程序启动时出现在 class 路径中才能自动注册。

代码中的@Grab 不是这种情况。

作为 grab 之后的解决方法,您可以执行此操作以调用所有驱动程序的自注册:

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