臭名昭著的java.sql.SQLException: No suitable driver found

128

我正在尝试将一个带有数据库功能的JSP添加到现有的Tomcat 5.5应用程序中(如果有帮助,应用名为GeoServer 2.0.0)。

该应用程序本身可以很好地访问Postgres数据库,所以我知道数据库是可用的,用户可以访问它,所有操作都正常。我正在尝试在我添加的JSP中进行数据库查询。我基本上直接使用了Tomcat datasource示例中的配置示例。必需的taglibs放置在正确的位置 - 如果只使用taglib引用,则不会出现任何错误,因此它能够找到这些JARs。Postgres JDBC驱动程序postgresql-8.4.701.jdbc3.jar位于$CATALINA_HOME/common/lib中。

以下是JSP的顶部:

<%@ taglib uri="http://java.sun.com/jsp/jstl/sql" prefix="sql" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>

<sql:query var="rs" dataSource="jdbc/mmas">
  select current_validstart as ValidTime from runoff_forecast_valid_time
</sql:query>

$CATALINA_HOME/conf/server.xml 中的相关部分,位于 <Engine> 内的 <Host> 中:

<Context path="/gs2" allowLinking="true">
  <Resource name="jdbc/mmas" type="javax.sql.Datasource"
      auth="Container" driverClassName="org.postgresql.Driver"
      maxActive="100" maxIdle="30" maxWait="10000"
      username="mmas" password="very_secure_yess_precious!"
      url="jdbc:postgresql//localhost:5432/mmas" />
</Context>

这些行是在webapps/gs2/WEB-INF/web.xml文件的</taglib>标签中的最后一行:

<resource-ref>
  <description>
     The database resource for the MMAS PostGIS database
  </description>
  <res-ref-name>
     jdbc/mmas
  </res-ref-name>
  <res-type>
     javax.sql.DataSource
  </res-type>
  <res-auth>
     Container
  </res-auth>
</resource-ref>

最后,异常情况:

   exception
    org.apache.jasper.JasperException: Unable to get connection, DataSource invalid: "java.sql.SQLException: No suitable driver"
    [...wads of ensuing goo elided]

请查看我的回答:https://dev59.com/XW035IYBdhLWcg3wNdPg#38656446 - Pacerier
22个回答

137
臭名昭著的java.sql.SQLException:找不到合适的驱动程序。
这个异常基本上有两个原因:

1. JDBC驱动程序未加载

Tomcat的情况下,您需要确保JDBC驱动程序放置在服务器自己的/lib文件夹中。

其他服务器也有类似的放置JAR文件的方式:

  • GlassFish:将JAR文件放在/glassfish/lib
  • WildFly:将JAR文件放在/standalone/deployments

或者,当您实际上不使用由服务器管理的连接池数据源(例如通过JNDI @Resource获取或在JPA的persistence.xml中配置),而是手动在WAR中的自定义类中以低级别的方式进行{{link1:DriverManager#getConnection()}}操作时,则需要将JDBC驱动程序放置在WAR的/WEB-INF/lib中并执行..

Class.forName("com.example.jdbc.Driver");

在您的自定义代码中,在第一个DriverManager#getConnection()调用之前,确保您不会吞咽/忽略任何可能被抛出的ClassNotFoundException,并且继续代码流程,就好像没有发生任何异常。另请参见我应该将JDBC驱动程序放在Tomcat连接池的哪里?提交表单到与数据库交互的Servlet导致空白页面

2. 或者,JDBC URL语法错误

您需要确保指定的JDBC URL符合JDBC驱动程序文档,并记住它通常是区分大小写的。当JDBC URL对于加载的任何驱动程序的Driver#acceptsURL()都不返回true时,您也会得到完全相同的异常。

PostgreSQL的情况下,这里有文档here

使用JDBC,数据库由URL(统一资源定位符)表示。对于PostgreSQL®,它采用以下形式之一:

  • jdbc:postgresql:database
  • jdbc:postgresql:/
  • jdbc:postgresql://host/database
  • jdbc:postgresql://host/
  • jdbc:postgresql://host:port/database
  • jdbc:postgresql://host:port/

对于MySQL,文档在这里中。

连接URL的通用格式如下:

协议//[主机][/数据库][?属性]

这是一个简单单主机连接URL的示例:

jdbc:mysql://host1:33060/sakila

对于Oracle,文档在这里中。

Thin驱动程序为所有这些类型提供以下URL格式: SID(Oracle不再建议使用): jdbc:oracle:thin:[<user>/<password>]@<host>[:<port>]:<SID> 服务: jdbc:oracle:thin:[<user>/<password>]@//<host>[:<port>]/<service> TNSNames: jdbc:oracle:thin:[<user>/<password>]@<TNSName>

另请参阅:


谢谢大家!抱歉第一次尝试没有在OP中,只是jdbc:postgresql:mmas(我已经尝试过其他方式!)。不幸的是,使用araqnid的URL,结果相同。昨晚,我用(ick)嵌入式Java替换了tablib的东西,现在它可以正常工作: try { Class.forName(“org.postgresql.Driver”).newInstance(); con = DriverManager.getConnection(“jdbc:postgresql:mmas”,“mmas”,“passwd”); stmt = con.createStatement(); rs = stmt.executeQuery(“select yada yada”); if(rs!= null && rs.next()){ //收获声望、财富、荣耀和美女Jakarta示例带有标签库,所以我开始那样做。 - Rick Wayne
啊,评论与代码格式化不太搭配。咳咳,是我这个新手表现出来了吗?(ZIIP!)无论如何,雅加达的例子都是关于使用sql:query语法而不仅仅是嵌入Java代码,我同意这是一种更加清晰的方式。我们不应该需要显式调用forName()和getConnection(),对吧?但是旧的丑陋的在表示层中插入驱动程序代码的方法第一次尝试就可以正常工作。所以我感到困惑,但现在这更多是一个维护/美观问题,而不是“这是坏的,修复它或者提高你翻转汉堡包的技能。” - Rick Wayne
在我看来,使用sql标签库比在scriptlets中使用JDBC略好一点...更喜欢控制器/视图模式,其中数据库操作是在前端完成的,而JSP只是用于显示处理。不过每个人都有自己的偏好,使用sql:query可以使事情保持简单:)(大概) - araqnid
我从未说过我同意使用JSTL SQL taglib,但这不是这个话题要讨论的主题。 - BalusC
2
谢谢,你提供的JDBC连接字符串格式非常有帮助! - Jay Taylor
对我来说,这意味着我包含的驱动程序在maven中找不到,但没有抛出错误(我找不到)。直到我查看了我的.m2文件夹,才发现jar文件不在那里。 - Matt Busche

22

我忘记将PostgreSQL JDBC驱动程序添加到我的项目中(Mvnrepository)。

Gradle:

// http://mvnrepository.com/artifact/postgresql/postgresql
compile group: 'postgresql', name: 'postgresql', version: '9.0-801.jdbc4'

Maven

<dependency>
    <groupId>postgresql</groupId>
    <artifactId>postgresql</artifactId>
    <version>9.0-801.jdbc4</version>
</dependency>

您也可以下载JAR文件并手动导入到您的项目中。


16
url="jdbc:postgresql//localhost:5432/mmas"

那个URL看起来不对,你是否需要以下内容?

url="jdbc:postgresql://localhost:5432/mmas"

12

我遇到了类似的问题。我的项目是基于动态 Web 项目(Java 8 + Tomcat 8),错误是关于 PostgreSQL 驱动程序异常:No suitable driver found

通过在调用 getConnection() 方法之前添加 Class.forName("org.postgresql.Driver"),问题得到解决。

以下是我的示例代码:

try {
            Connection conn = null;
            Class.forName("org.postgresql.Driver");
            conn = DriverManager.getConnection("jdbc:postgresql://" + host + ":" + port + "/?preferQueryMode="
                    + sql_auth,sql_user , sql_password);
        } catch (Exception e) {
            System.out.println("Failed to create JDBC db connection " + e.toString() + e.getMessage());
        }

3

简介:

  • 解决方案2(推荐)::

    • 1. 将mysql-connector-java-8.0.28.jar文件放入<您安装Tomcat的位置>/lib中。
  • 解决方案1::

    • 1. 将mysql-connector-java-8.0.28.jar文件放入WEB-INF/lib中。
    • 2. 在Servlet Java代码中使用Class.forName("com.mysql.cj.jdbc.Driver");

解决方案1 (原始答案) //-20220304

简短说明:

  1. 确保在WEB-INF/lib中有mysql-connector-java-8.0.28.jar文件
  2. 确保使用Class.forName("com.mysql.cj.jdbc.Driver");

jar & class for jdbc connect


额外说明(不重要),基于我的尝试(可能有错误)::

  • 1.1 直接将jar文件放入Java build path中不起作用

  • 1.2 将jar文件放入Data management > Driver Def > MySQL JDBC Driver >然后将其添加为Java Build path库不起作用。

  • 1.3 => 它必须在WEB-INF/lib中(我不知道为什么)

  • 1.4 使用版本mysql-connector-java-8.0.28.jar有效,在Eclipse的MySQL JDBC Driver设置中只有版本5.1可用,不要理会它。

    <查看如何使用Eclipse数据库管理透视图连接到MySql 8.0数据库>

  •     Class.forName("com.mysql.cj.jdbc.Driver");
        Class.forName("com.mysql.jdbc.Driver");
    

    both works, but the Class.forName("com.mysql.jdbc.Driver"); is deprecated.

    Loading class `com.mysql.jdbc.Driver'. This is deprecated. The new driver class is `com.mysql.cj.jdbc.Driver'. The driver is automatically registered via the SPI and manual loading of the driver class is generally unnecessary.
    

    <see https://www.yawintutor.com/no-suitable-driver-found-for-jdbcmysql-localhost3306-testdb/ >

  • 如果您想连接到MySQL数据库,可以使用名为Connector/的类型4驱动程序,该驱动程序可从MySQL网站免费获取。但是,此驱动程序通常包含在Tomcat的lib目录中。因此,您通常不需要从MySQL网站下载此驱动程序。

    -- Murach的Java Servlets和JSP

    我找不到作者所说的Tomcat驱动程序,我需要使用mysql-connector-java-8.0.28.jar。<(已划掉)请参见下面更新的答案soln2>

  • 不过,如果您正在使用旧版本的Java,则需要使用Class类的forName方法显式加载驱动程序,然后才能调用getConnection方法

    即使使用JDBC 4.0,有时也会收到“找不到合适的驱动程序”的消息。在这种情况下,您可以使用Class类的forName方法显式加载驱动程序。但是,如果自动驱动程序加载有效,则通常有理由从代码中删除此方法调用。

    如何在JDBC 4.0之前加载MySQL数据库驱动程序

    Class.forName{"com.mysql.jdbc.Driver");

    -- Murach的Java Servlets和JSP

    我必须在我的系统中使用Class.forName(“com.mysql.cj.jdbc.Driver”)才能正常工作,没有自动类加载。不确定为什么。<(已划掉)请参见下面更新的答案soln2>

  • 当我在Eclipse中使用普通Java项目而不是动态Web项目时,

    我只需要直接将mysql-connector-java-8.0.28.jar添加到Java Build Path中,

    然后我就可以无问题地连接到JDBC。

    但是,如果我使用动态Web项目(在这种情况下),这两个严格规则适用(jar位置和类加载)。

    <请参见TOMCAT ON ECLIPSE java.sql.SQLException: No suitable driver found for jdbc:mysql>


Soln2(更新的答案)//-20220305_12

简而言之:

  • 1. 将 mysql-connector-java-8.0.28.jar 文件放置在 <您安装Tomcat的位置>/lib 中。

    例如:G:\pla\Java\apache-tomcat-10.0.16\lib\mysql-connector-java-8.0.28.jar

    (对于Eclipse中的 Dynamic Web Project,则会自动将jar文件放置在项目的Java build path > Server Runtime [Apache Tomcat v10.0]中。)

put jar in Tomcat/lib


额外说明:

对于soln1:

  1. mysql-connector-java-8.0.28.jar 文件放置在 WEB-INF/lib 中。
  2. 在Servlet Java代码中使用 Class.forName("com.mysql.cj.jdbc.Driver");

这将创建一个警告:

WARNING: The web application [LearnJDBC] appears to have started a thread named [mysql-cj-abandoned-connection-cleanup] but has failed to stop it. This is very likely to create a memory leak. Stack trace of thread:

<参见The web application [] appears to have started a thread named [Abandoned connection cleanup thread] com.mysql.jdbc.AbandonedConnectionCleanupThread,该答案指导我使用soln2。

关于soln2:

    1. put mysql-connector-java-8.0.28.jar file in the <where you install your Tomcat>/lib.

    this will create an INFO:

    INFO: At least one JAR was scanned for TLDs yet contained no TLDs. Enable debug logging for this logger for a complete list of JARs that were scanned but no TLDs were found in them. Skipping unneeded JARs during scanning can improve startup time and JSP compilation time.
    
  • you can just ignore it.

    <see How to fix "JARs that were scanned but no TLDs were found in them " in Tomcat 9.0.0M10 >

  • (you should now understand what Murach’s Java Servlets and JSP was talking about: the jar in Tomcat/lib & the no need for Class.forName("com.mysql.cj.jdbc.Driver");)

  • to kinda fix it //-20220307_23

    Tomcat 8.5. Inside catalina.properties, located in the /conf directory set: tomcat.util.scan.StandardJarScanFilter.jarsToSkip=\*.jar

    How to fix JSP compiler warning: one JAR was scanned for TLDs yet contained no TLDs?

    skip scan in Tomcat/lib jar


3

请勿仅提供链接回答 - 简要描述其背后的内容! - monamona
欢迎提供解决方案的链接,但请确保您的答案即使没有链接也很有用。添加链接周围的上下文,这样其他用户就会知道它是什么以及为什么存在,并引用您链接到的页面中最相关的部分,以防目标页面不可用。那些几乎只有链接而没有实质性内容的回答可能会被删除 - Peter

2

使用指向驱动程序JAR文件的CLASSPATH环境变量运行java,例如:

CLASSPATH='.:drivers/mssql-jdbc-6.2.1.jre8.jar' java ConnectURL

其中drivers/mssql-jdbc-6.2.1.jre8.jar是驱动程序文件的路径(例如SQL Server的JDBC)。

ConnectURL是该驱动程序的示例应用程序(samples/connections/ConnectURL.java),通过javac ConnectURL.java编译。


2
无论这个线程变得多老,人们仍然会遇到这个问题。
我的情况:我已经安装了最新的OpenJDK和maven。我尝试过上面提供的所有方法,包括使用或不使用maven以及在StackOverflow的姐妹帖子上的解决方案。我没有使用任何IDE或其他工具,只是从裸机CLI运行以演示核心逻辑。
以下是最终有效的方法:
1. 从官方网站下载驱动程序(对我来说是MySQL https://www.mysql.com/products/connector/)。在此处使用您的版本。
2. 将给定的jar文件解压缩到与您的Java项目相同的目录中。您将获得一个类似于此的目录结构。如果您仔细查看,这与我们使用Class.forName(....)尝试执行的操作完全相关。我们需要的文件是com/mysql/jdbc/Driver.class
3. 编译包含代码的Java程序。
javac App.java

现在运行以下命令,将目录作为模块加载:
java --module-path com/mysql/jdbc -cp ./ App

这将手动加载(提取的)包,您的Java程序会找到必需的 Driver 类。


  • 请注意,此操作是为 mysql 驱动程序执行的,其他驱动程序可能需要进行轻微更改。
  • 如果您的供应商提供了 .deb 映像,则可以从 /usr/share/java/your-vendor-file-here.jar 获取 jar 文件。

1
一种非常愚蠢的错误可能会导致在JDBC URL连接的开头添加空格。
我的意思是:
假设您不小心将JDBC URL设置为:
String jdbcUrl=" jdbc:mysql://localhost:3306/web_customer_tracker?useSSL=false&serverTimeZone=UTC";

注意url开头有一个空格,这会导致错误。

正确的方式应该是:

String jdbcUrl="jdbc:mysql://localhost:3306/web_customer_tracker?useSSL=false&serverTimeZone=UTC";

(注意开头没有空格,URL末尾可以加空格,但最好不要)


1
值得注意的是,当Windows阻止下载被认为不安全的文件时,也可能会出现这种情况。可以通过右键单击jar文件(例如ojdbc7.jar),并在底部勾选“取消阻止”框来解决此问题。 Windows JAR文件属性对话框:
Windows JAR文件属性对话框

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