为什么Class.forName似乎没有向DriverManager注册驱动程序



作为JDBC的新手,我被教导使用Class.forNameDriverManager注册驱动程序,这似乎对我的代码不起作用:

public static void main(String[] args)
{
System.out.println(DriverManager.drivers().count());
// clear all loaded drivers
Iterator<Driver> it = DriverManager.drivers().iterator();
while (it.hasNext())
{
try { DriverManager.deregisterDriver(it.next()); }
catch (SQLException e) { e.printStackTrace(); }
}
System.out.println(DriverManager.drivers().count());
// register mysql driver with forName
try { Class.forName("com.mysql.cj.jdbc.Driver"); }
catch (ClassNotFoundException e) { e.printStackTrace(); }
System.out.println(DriverManager.drivers().count());
// register with constructor - works fine
try { DriverManager.registerDriver(new com.mysql.cj.jdbc.Driver()); }
catch (SQLException e) { e.printStackTrace(); }
System.out.println(DriverManager.drivers().count());
}

每当我编译和运行时,总是会产生1、0、0、1。我哪里错了?

JDBC驱动程序在现代Java中自动注册

你说:

我被教导使用Class.forName

你的老师已经过时了。

在现代Java中,您不再需要调用Class.forName。JDBC驱动程序现在通过Java服务提供程序接口(SPI(自动加载。如果想知道这是如何工作的,请参阅此问题。

如果JDBC驱动程序未能自动注册,请验证它是否包含在项目中,或者如果在Jakarta EE(Java EE(服务器中,请验证该环境中的正确位置。您没有发布足够的关于您的开发和部署场景的详细信息供我们诊断。并验证您是否拥有正确的版本,该版本通常应该支持JDBC 4.x(4.3是最新版本(。

如果您仍然有问题,请编写一个一次性控制台应用程序,该应用程序除了连接到您的数据库之外,什么都不做。尽可能多地消除复杂性和干扰。

关于你显示的代码,我不知道你为什么要注销任何司机。基本上,你在问题中显示的所有代码都应该是不必要的。

DataSource

此外,通常最好使用DataSource作为连接数据库的方式。DataSource对象包含连接所需的信息:服务器地址、端口号、用户名、密码以及特定于数据库服务器产品的各种专有设置。

我已经写了一些关于堆栈溢出的答案,并为MySQL、Postgres和&H2。就像这个。我建议你从我和Stack Overflow上的许多其他优秀作者那里搜索这样的例子。

这里有一个这样的例子。这里显示的代码应该足够了,因为MySQL驱动程序应该是自动加载的。

private DataSource configureDataSource ( )
{
System.out.println( "INFO - `configureDataSource` method. " + Instant.now() );
com.mysql.cj.jdbc.MysqlDataSource dataSource = Objects.requireNonNull( new com.mysql.cj.jdbc.MysqlDataSource() );  // Implementation of `DataSource`.
dataSource.setServerName( "db-mysql-lon2-722-do-user-89973-1.x.db.ondigitalocean.com" );
dataSource.setPortNumber( 24_090 );
dataSource.setDatabaseName( "defaultdb" );
dataSource.setUser( "scott" );
dataSource.setPassword( "tiger" );
return dataSource;
}

用法:

Connection conn = myDataSource.getConnection() ;

当然,您应该获得满足您需求的DataSource实现。例如,一些提供新的连接,而另一些提供连接池。有些是由数据库的供应商提供的,有些是第三方的。

由于Java 6(假设初始类路径上有JDBC 4.0或更高版本的驱动程序(,JDBC驱动程序会自动加载。这意味着驱动程序在DriverManager被类加载和初始化时自动加载。

驱动程序类的静态初始值设定项向驱动程序管理器注册驱动程序。该静态初始值设定项在加载类时运行。由于驱动程序类已经加载,随后的Class.forName返回已经加载的类,并且静态初始值设定项不会再次运行,因此不会向DriverManager注册任何内容。

换句话说:

  1. DriverManager是类加载的,并使用ServiceLoader加载驱动程序
    • com.mysql.cj.jdbc.Driver通过ServiceLoader加载,其静态初始值设定项向DriverManager注册一个实例
  2. 您从DriverManager中删除所有驱动程序
  3. 您拨打Class.forName("com.mysql.cj.jdbc.Driver")
    • 给定类已经加载,Java返回已经加载的类
    • 由于静态初始化程序不再运行,因此未注册任何内容
  4. 您可以手动向DriverManager注册一个实例(顺便说一句,这不是您通常应该做的事情,DriverManager.registerDriver是供JDBC驱动程序调用的(

最新更新