Class.forName("com.mysql.jdbc.Driver") 没有在 jar 文件中查找该类

Posted

技术标签:

【中文标题】Class.forName("com.mysql.jdbc.Driver") 没有在 jar 文件中查找该类【英文标题】:Class.forName("com.mysql.jdbc.Driver") is not looking in jar file for the class 【发布时间】:2020-11-18 04:04:21 【问题描述】:

我是 Java 新手,学习曲线陡峭。我有一个旧的 ColdFusion 10 应用程序,我希望逐步使用 Java 类而不是 ColdFusion CFC 作为迁移出 CF 领域的一种方式。我可以让所有这些都适用于我迄今为止编写的课程。

我现在要测试如何使用 CF 正在使用的相同 java 连接器与 mysql 数据库交互(在这种情况下为 mysql-connector-java-commercial-5.1.25-bin.jar,如使用在我的本地开发机器上)。

为了测试简单起见,我的测试类和连接器 jar 都在同一个文件夹中(Windows 机器)。

问题在于这个声明:Class.forName("com.mysql.jdbc.Driver"); - 我收到的是Exception in thread "main" java.lang.ClassNotFoundException: com.mysql.jdbc.Driver

现在,如果我解压缩连接器 jar,使文件夹出现在我的测试文件夹中:com\mysql\jdbc\Driver.class(以及 jar 中的所有其他文件),我的测试类工作正常并且记录被插入我的数据库表。酷!

但是,如果我删除了实际的文件夹并依赖于 jar 本身,我就会得到 ClassNotFoundException。

在我的其他学习/测试中(使用我自己生成的 jar 文件),正在从 jar 中提取一个相关的类。但是对于这个 mysql 测试的这个特定的 jar,它不是。

我应该注意什么 - 显然我错过了什么?

谢谢。我真的很期待进入 Java 领域。 :-)

穆雷

【问题讨论】:

您是在编写一个普通的 Java 应用程序,还是一个使用 JSP 或 Servlet 等的 Web 应用程序?也就是说,您使用的是 Jetty 或 Tomcat 或 Glassfish 等 servlet 容器吗? 谢谢。纯香草。没有依赖关系。基本上是一个概念验证(对于我的编程技能和其他任何东西一样多;-)) 使用 Class.forName 加载 JDBC 驱动程序自 2006 年 Java 6 发布以来已过时。此外,请使用 Maven 或 Gradle;这是他们的工作。 是的。这就是我现在需要使用的版本。请参阅下面的评论。谢谢。 【参考方案1】:

在当前目录中拥有 JAR 文件是不够的。您必须告诉 java 将 mysql jar 文件包含在 classpath 中。这可以通过在 java 命令行中使用-cp 参数或CLASSPATH 环境变量来指定。

【讨论】:

谢谢。我确实看到了其他类似的答案,但无法使其发挥作用。当使用文件夹结构(不是 jar)运行时,我这样做:C:\mypath\JavaTest\mySqlTest>java MySQLAccessMain 有效。我尝试使用java -classpath etc,但显然语法错误。那么,请问应该怎么做? C:\mypath\JavaTest\mySqlTest>java -classpath mysql-connector-java-commercial-5.1.25-bin.jar MySQLAccessMain throws Error: Could not find or load main class MySQLAccessMain 和我各种尝试正确的路径都失败了。 :-( 使用java -classpath .;mysql-connector-java-commercial-5.1.25-bin.jar MySQLAccessMain。这 ”。;”在开始时告诉 java 也在当前目录中搜索 .class 文件,这是它将找到 MySQLAccessMain 的位置。 就是这样!非常感谢!我将在下面发布其他 CF 难民的完整答案。 ;-) 其实这只是一个“Java 101”问题:如何在运行时类路径中添加外部库。 是的,我确定,而且我只有 2 天,所以我在 Java 100 上,我想。 ;-) 通过研究如何在 ColdFusion 环境中进行操作变得更加复杂。谢谢!【参考方案2】:

我使用Postgres 和H2 而不是MySQL。所以我不确定你的问题可能是关于 MySQL 的。但是我现在能够使用在运行时提供的 MySQL 驱动程序创建一个新项目。请继续阅读以遵循我的示例。

Maven 驱动的项目示例

如今的 Java 项目通常由 dependency management 和 build automation 工具管理,例如 Maven、Gradle 或 Ivy。

我使用 Maven Quickstart Archetype 开始了一个新的 Java 项目。

在该原型提供的POM file 中,我做了两处更改:

<maven.compiler.source><maven.compiler.target>1.7 更改为 11 以使用 Java 11,即当前的 long-term support 版本。 为您提到的 JDBC 驱动程序添加了一个依赖项:
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.22</version>
</dependency>

然后我在App 类的main 方法中添加了一行。

        try
        
            Class.forName("com.mysql.jdbc.Driver");
            System.out.println("Found class for JDBC driver.");
        
        catch ( ClassNotFoundException e )
        
            e.printStackTrace();
        
        System.out.println( "Hello World!" );

当我运行它时,没有抛出异常。所以似乎成功找到了这个类。

完整的 POM:

<?xml version="1.0" encoding="UTF-8"?>

<project xmlns = "http://maven.apache.org/POM/4.0.0"
         xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation = "http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>work.basil.example</groupId>
    <artifactId>jdbc-driver-in-jar</artifactId>
    <version>1.0-SNAPSHOT</version>

    <name>jdbc-driver-in-jar</name>
    <!-- FIXME change it to the project's website -->
    <url>http://www.example.com</url>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
    </properties>

    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.11</version>
            <scope>test</scope>
        </dependency>

        <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.22</version>
        </dependency>


    </dependencies>

    <build>
        <pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
            <plugins>
                <!-- clean lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#clean_Lifecycle -->
                <plugin>
                    <artifactId>maven-clean-plugin</artifactId>
                    <version>3.1.0</version>
                </plugin>
                <!-- default lifecycle, jar packaging: see https://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_jar_packaging -->
                <plugin>
                    <artifactId>maven-resources-plugin</artifactId>
                    <version>3.0.2</version>
                </plugin>
                <plugin>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <version>3.8.0</version>
                </plugin>
                <plugin>
                    <artifactId>maven-surefire-plugin</artifactId>
                    <version>2.22.1</version>
                </plugin>
                <plugin>
                    <artifactId>maven-jar-plugin</artifactId>
                    <version>3.0.2</version>
                </plugin>
                <plugin>
                    <artifactId>maven-install-plugin</artifactId>
                    <version>2.5.2</version>
                </plugin>
                <plugin>
                    <artifactId>maven-deploy-plugin</artifactId>
                    <version>2.8.2</version>
                </plugin>
                <!-- site lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#site_Lifecycle -->
                <plugin>
                    <artifactId>maven-site-plugin</artifactId>
                    <version>3.7.1</version>
                </plugin>
                <plugin>
                    <artifactId>maven-project-info-reports-plugin</artifactId>
                    <version>3.0.0</version>
                </plugin>
            </plugins>
        </pluginManagement>
    </build>
</project>

完整的应用类:

package work.basil.example;

/**
 * Hello world!
 *
 */
public class App 

    public static void main( String[] args )
    
        try
        
            Class.forName("com.mysql.jdbc.Driver");
            System.out.println("Found class for JDBC driver.");
        
        catch ( ClassNotFoundException e )
        
            e.printStackTrace();
        
        System.out.println( "Hello World!" );
    

一些注意事项:

我在控制台输出中注意到特定的 JDBC driver 已过时。您应该调查一下现在要使用的正确 JDBC 驱动程序。

加载类com.mysql.jdbc.Driver'. This is deprecated. The new driver class is com.mysql.cj.jdbc.Driver'。驱动通过SPI自动注册,一般不需要手动加载驱动类。

Class.forName 是加载 JDBC 驱动程序的老式方法,不再需要。几年前,JDBC 驱动程序加载得到了很大改进。今天的 JDBC 驱动程序是通过 Java 的 Service Provider Interface (SPI) 工具加载的。但是 Class.forName 代码可能仍然有助于探索您的这个问题,以验证可以在您的 classpath 上找到该课程。

通常最好使用DataSource 来获取数据库连接。您的 JDBC 驱动程序可能提供了DataSource 的实现。此类将保存与数据库服务器建立连接所需的信息,例如查找数据库服务器的地址,以及用于向数据库服务器进行身份验证的用户名和密码。

【讨论】:

哇!感谢罗勒的详细回答。我使用旧版 mysql 连接器的原因是我的 ColdFusion 主机公司只提供 CF10 和 Java 1.6。有大量的 CFC 文件,我无法一次将它们全部转换为 Java。由于 CF 是在 Java 上构建的,因此可以混合搭配 CF 和 Java,所以我的想法是使用我所拥有的(Java 1.6)并将业务逻辑逐步转换为 Java 类,直到我达到放弃 CF 的地步完全使用 Java 完成所有工作。那时我可以升级到现代工具。 :-) @Murrah 顺便说一句,我喜欢使用 Vaadin.com 在服务器端用纯 Java 构建 Web 应用程序,以便在标准 Web 技术(HTML、CSS、javascript)上自动呈现 UI客户端。 谢谢,我去看看【参考方案3】:

好的。感谢您所有快速、有用和有趣的输入! :-)

两件事:

    使用来自@schtever 的java 答案运行:java -classpath .;mysql-connector-java-commercial-5.1.25-bin.jar MySQLAccessMain。我不知道.; 语法。谢谢。

    由于我最终将在 ColdFusion 上下文中执行该类(至少现在是这样),因此以下 CFM 可以正常工作,因为当然,ColdFusion 会处理指向其 jar 堆的类路径。

这是java测试类

public class MySQLAccessMain 
  public static void main(String[] args) throws Exception 
    MySQLAccess dao = new MySQLAccess();
    dao.readDataBase(); // Run some fixed SELECT and INSERT tests
  

这是 CFM 版本

var dao = createObject("java","MySQLAccess");
dao.readDataBase();

当然还有 application.cfc:

this.javaSettings = 
    loadPaths: [
        "/myjava"  // Where MySQLAccess.class goes
    ]
    ,loadColdFusionClassPath: true // If this is true you can also use the coldfusion builtin java classes
    ,reloadOnChange = true
    ,watchInterval = 2
;

:-) 快乐的露营者!再次感谢。

【讨论】:

最后一条评论 - 分号取决于平台。在 *nix 系统上,它是一个冒号。另外,我可以要求您接受我的回答吗?谢谢! 再次感谢。完毕。对不起,我以为我接受了。非常感谢。

以上是关于Class.forName("com.mysql.jdbc.Driver") 没有在 jar 文件中查找该类的主要内容,如果未能解决你的问题,请参考以下文章

为啥我找不到 Class.forName("com.mysql.jdbc.Driver"); 的异常[复制]

h2 数据库的 ClassNotFound 异常 class.forname("org.h2.Driver")

连接数据库时 Class.forName("oracle.jdbc.driver.OracleDriver") 的实际用途是啥?

Class.forName("com.mysql.jdbc.Driver").newInstance()

Class.forName("com.mysql.jdbc.Driver") 没有在 jar 文件中查找该类

Class.forName(Class) 在特定目录中?