java - 我必须在哪里放置 Tomcat 连接池的 JDBC 驱动程序?

标签 java tomcat jdbc connection-pooling

所以我已经弄清楚了我的错误,现在我只是在寻找一些关于到底发生了什么的见解。我使用的是 Apache Tomcat 版本 7.0.32。我正在使用 this tutorial为 JDBC 设置池。在我的 META-INF 文件夹中,我创建了一个 context.xml 文件并将其放入其中。

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

<Context>
    <Resource type="javax.sql.DataSource" name="jdbc/gmustudent"
        factory="org.apache.tomcat.jdbc.pool.DataSourceFactory" 
        driverClassName="com.mysql.jdbc.Driver"
        url="jdbc:mysql://localhost:3306/official"
        username="root" password="root"
        maxActive="100" maxIdle="20" minIdle="15" initialSize="15" maxWait="10000" />
</Context>

我在写这篇文章的时候遇到了这个错误

WARNING: Unexpected exception resolving reference
java.sql.SQLException: com.mysql.jdbc.Driver
    at org.apache.tomcat.jdbc.pool.PooledConnection.connectUsingDriver(PooledConnection.java:254)
    at org.apache.tomcat.jdbc.pool.PooledConnection.connect(PooledConnection.java:182)
    at org.apache.tomcat.jdbc.pool.ConnectionPool.createConnection(ConnectionPool.java:699)
    at org.apache.tomcat.jdbc.pool.ConnectionPool.borrowConnection(ConnectionPool.java:631)
    at org.apache.tomcat.jdbc.pool.ConnectionPool.init(ConnectionPool.java:485)
    at org.apache.tomcat.jdbc.pool.ConnectionPool.<init>(ConnectionPool.java:143)
    at org.apache.tomcat.jdbc.pool.DataSourceProxy.pCreatePool(DataSourceProxy.java:116)
    at org.apache.tomcat.jdbc.pool.DataSourceProxy.createPool(DataSourceProxy.java:103)
    at org.apache.tomcat.jdbc.pool.DataSourceFactory.createDataSource(DataSourceFactory.java:539)
    at org.apache.tomcat.jdbc.pool.DataSourceFactory.getObjectInstance(DataSourceFactory.java:237)
    at org.apache.naming.factory.ResourceFactory.getObjectInstance(ResourceFactory.java:143)
    at javax.naming.spi.NamingManager.getObjectInstance(NamingManager.java:304)
    at org.apache.naming.NamingContext.lookup(NamingContext.java:843)
    at org.apache.naming.NamingContext.lookup(NamingContext.java:154)
    at org.apache.naming.NamingContext.lookup(NamingContext.java:831)
    at org.apache.naming.NamingContext.lookup(NamingContext.java:168)
    at org.apache.catalina.core.NamingContextListener.addResource(NamingContextListener.java:1061)
    at org.apache.catalina.core.NamingContextListener.createNamingContext(NamingContextListener.java:671)
    at org.apache.catalina.core.NamingContextListener.lifecycleEvent(NamingContextListener.java:270)
    at org.apache.catalina.util.LifecycleSupport.fireLifecycleEvent(LifecycleSupport.java:119)
    at org.apache.catalina.util.LifecycleBase.fireLifecycleEvent(LifecycleBase.java:90)
    at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5173)
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
    at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1559)
    at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1549)
    at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303)
    at java.util.concurrent.FutureTask.run(FutureTask.java:138)
    at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
    at java.lang.Thread.run(Thread.java:680)
Caused by: java.lang.ClassNotFoundException: com.mysql.jdbc.Driver
    at java.net.URLClassLoader$1.run(URLClassLoader.java:202)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:306)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:247)
    at java.lang.Class.forName0(Native Method)
    at java.lang.Class.forName(Class.java:247)
    at org.apache.tomcat.jdbc.pool.PooledConnection.connectUsingDriver(PooledConnection.java:246)
    ... 29 more
Oct 31, 2012 11:23:25 AM org.apache.catalina.core.NamingContextListener addResource
WARNING: Failed to register in JMX: javax.naming.NamingException: com.mysql.jdbc.Driver
Oct 31, 2012 11:23:25 AM org.apache.coyote.AbstractProtocol start
INFO: Starting ProtocolHandler ["http-bio-8086"]
Oct 31, 2012 11:23:25 AM org.apache.coyote.AbstractProtocol start
INFO: Starting ProtocolHandler ["ajp-bio-8009"]
Oct 31, 2012 11:23:25 AM org.apache.catalina.startup.Catalina start
INFO: Server startup in 794 ms

只有在我的 context.xml 文件中包含此语句时才会出现此错误。当我删除它时没有错误。

factory="org.apache.tomcat.jdbc.pool.DataSourceFactory" 

我想确保我拥有它的原因是因为在 apache tomcat 教程中它说

factory is required, and the value should be org.apache.tomcat.jdbc.pool.DataSourceFactory

然后我对 SO 做了一些研究,发现一个帖子说你需要添加 this jar到你的 lib 文件夹,如果你有一个旧版本的 tomcat。所以我添加了 jar,现在它可以工作了,但我想了解一些关于到底发生了什么的信息,因为我使用的是最新的 tomcat 版本。那么,为什么当我指定工厂时会出现错误。我要添加的这个 jar 是什么,为什么关于它的文档很少?非常感谢有关这里发生的事情的任何信息。

最佳答案

JDBC 驱动程序必须对与数据源工厂本身相同的类加载器可见。数据源工厂库放在Tomcat自己的/lib文件夹中,由Tomcat的“通用”类加载器加载。

您的问题听起来很像您将 JDBC 驱动程序放在 webapp 的 /WEB-INF/lib 中。 Web 应用程序的 /WEB-INF/lib 对于“通用”类加载器是不可见的。因此,从技术上讲,您必须将 JDBC 驱动程序放在 Tomcat 自己的 /lib 文件夹中(或者,至少,放在由 common.loader 设置指定的可配置路径中 /conf/catalina.properties) 以使其对数据源工厂可见。

或者,正如您所尝试的那样,将数据源工厂复制到 /WEB-INF/lib 中也会修复它。 webapp 的 /WEB-INF/lib 在类加载方面比 Tomcat 的 /lib 文件夹具有更高的优先级。因此,如果在 /WEB-INF/lib 中找到数据源工厂,它将从那里加载。由于 JDBC 驱动程序也在那里,因此可以看到。然而,这不是您具体问题的正确解决方案,这更像是一种解决方法,因此您不应该这样做。

没有专门针对此问题的文档。 Tomcat Class Loader HOW-TO然而,将有助于理解 Tomcat 中的类加载层次结构。

screen shot showing Tomcat folder with nested "lib" folder with nested JDBC driver .jar file

另见:

关于java - 我必须在哪里放置 Tomcat 连接池的 JDBC 驱动程序?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35817158/

相关文章:

java - 使用 JAXB 解析没有容器标签的抽象对象

java - 我的 'decrypt' 代码无法正常工作

java - 使用 Keycloak 保护 Tomcat 应用程序时出现 HTTP 403 forbidden 错误

java - 需要将大型 QueryRunner 结果流式传输到文件,似乎存储在内存中

java - Spring StoredProcedure 结果集值修剪

java - 序列化时间戳转换为秒

java - 如果在私有(private)构造函数中初始化,从静态方法访问时是否保证私有(private)静态字段为非空

java - Spring 3.0 webapp NoClassDefFoundError - 类路径问题

angularjs - 无法运行tomcat7

java - java中如何处理表列中的空值?