在 /WEB-INF/lib 中使用 JBDC 4.0 驱动程序,但仍然需要 Class#forName() 来加载它

Posted

技术标签:

【中文标题】在 /WEB-INF/lib 中使用 JBDC 4.0 驱动程序,但仍然需要 Class#forName() 来加载它【英文标题】:Using JBDC 4.0 driver in /WEB-INF/lib and yet Class#forName() is still required to load it 【发布时间】:2013-06-27 22:43:58 【问题描述】:

我正在尝试通过 jsp 访问我的数据库,我有以下代码:

<% 
        String username = request.getParameter("username");
        String password = request.getParameter("password");
        String value = "vuoto";


        Class.forName("com.mysql.jdbc.Driver");
        Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/onlinebookstore", "root", "sesame");
        Statement statement = connection.createStatement();
        ResultSet result = statement.executeQuery("SELECT * FROM users WHERE email = '" + username + "' " + "AND" + " password = '" + password + "'");
        if(result.next()) 
           value = "eccomi";
        
        connection.close();
%>

我不明白为什么需要使用 Class.forName,因为我从 JDBC 4.0 中读到它没有必要,但如果我删除该语句,它就不起作用。在我的库中,我添加了 MySQL JDBC Driver -mysql-connector-java-5.1.23-bin.jar

【问题讨论】:

我想知道有没有人告诉你从 JSP 打开连接和查询数据库是个坏主意... 我知道,我只是在做一些尝试 【参考方案1】:

我将忽略问题中公开的在 JSP 中编写 Java 代码的不良编程实践——当你想使用原始 Java 代码而不是 html 拦截 HTTP 请求/响应时,你应该真正开始习惯创建沙箱 servlet .


至于具体问题,这确实是意料之中的行为。对于初学者,JDBC 4.0 驱动程序是使用ServiceLoader API 自动加载的。我们来看看它的javadoc;这是相关性的摘录(javadoc的第5段;强调我的):

如果一个特定的具体提供者类在多个配置文件中被命名,或者在同一个配置文件中被多次命名,那么重复的将被忽略。命名特定提供程序的配置文件不需要与提供程序本身位于相同的 jar 文件或其他分发单元中。 必须可以从最初查询配置文件的同一个类加载器访问提供程序;请注意,这不一定是实际加载文件的类加载器。

负责查询JAR 的/META-INF/services 文件夹中的配置文件的是servletcontainer 本身,而不是webapp。所以,本质上,JAR 必须放在 servletcontainer 自己的运行时类路径中,而不是 webapp 自己的运行时类路径中。 webapp 的 /WEB-INF/lib 文件夹被 webapp 的运行时类路径覆盖,而不是 servletcontainer 的,因此基本上是错误的位置。

您在任何地方都没有说明正在使用的 servletcontainer,但根据您在其他一些问题中发现的堆栈跟踪,我猜它是 Apache Tomcat。在这种情况下,必须将 JDBC 驱动 JAR 文件放在 Tomcat 自己的 /lib 文件夹中,以便正确利用 ServiceLoader 机制自动加载的 JDBC 驱动。

【讨论】:

【参考方案2】:

尽管 jar 是类路径的一部分,但您编写的代码都没有引用 Driver 类。我相信 Driver 类在其静态块之一中向 JDBC 注册自身,因此它必须由类加载器加载,才能执行该静态块,并且 JDBC api 才能使用该驱动程序类。 Class.forName 加载类,因此需要它。

另外,正如有人回答并出于某种原因删除了该帖子,只有与 JDBC 4.0 兼容的驱动程序不需要 Class.forName,但较旧的驱动程序需要。

【讨论】:

【参考方案3】:

JDBC 驱动程序mysql-connector-java-5.1.23-bin.jar 是类型 4 驱动程序,它 符合JDBC 3.0JDBC 4.0 规范。

但要利用 JDBC 4.0 规范,您需要java 6 或更高版本。

如果您有较旧的 java,它将考虑 JDBC 3.0 规范并且不会自动加载 Driver

您可以在下载的 Zip 文件中提供的文档中找到此信息。

【讨论】:

我有java7,那我看不懂【参考方案4】:

在我的环境中,此代码在没有 Class.forName 的情况下有效。

public class Test 
  public static void main(String[] args) 

    //Class.forName("com.mysql.jdbc.Driver");
    Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test", "root", "sesame");

    // do some query
  

所以我认为你的问题可能是类加载器问题。 如果您使用的是 Tomcat,this answer 会有所帮助。

【讨论】:

以上是关于在 /WEB-INF/lib 中使用 JBDC 4.0 驱动程序,但仍然需要 Class#forName() 来加载它的主要内容,如果未能解决你的问题,请参考以下文章

如何在eclipse中使用Ivy + IvyDE将不同的jar放到lib和web-inf/lib中

如何签署放置在 maven 中 /WEB-INF/lib 目录中的 JAR 文件

在tomcat类路径中包含web-inf / lib中的目录

在 POM 的 WEB-INF\lib 中添加一个 jar

myeclipse 在web-inf/lib中导入包

/WEB-INF/classes 与 /WEB-INF/lib