当前位置: 首页 > 知识库问答 >
问题:

通过资源加载jdbc驱动程序(Tomcat 7)

慕通
2023-03-14

我正在尝试使用tomcat jdbc连接池,并在我的应用程序context.xml文件中定义了它。

<Context>
    <Resource auth="Container" name="jdbc/iup" type="javax.sql.DataSource"
              maxActive="300" maxIdle="30" maxWait="20000"
              username="${db.username}" password="${db.password}" driverClassName="net.sf.log4jdbc.DriverSpy"
              url="jdbc:log4jdbc:sqlserver://${db.server};databaseName=${db.name}"/>
</Context>

类<code>net.sf.log4jdbc。DriverSpy是在<code>log4jdbc4-1.2.jar

Tomcat使用它的基本CDATA源类加载驱动程序:

if (driverClassName != null) {
            try {
                try {
                    if (driverClassLoader == null) {
                        Class.forName(driverClassName);
                    } else {
                        Class.forName(driverClassName, true, driverClassLoader);
                    }
                } catch (ClassNotFoundException cnfe) {
                    driverFromCCL = Thread.currentThread(
                            ).getContextClassLoader().loadClass(
                                    driverClassName);
                }
            } catch (Throwable t) {
                String message = "Cannot load JDBC driver class '" +
                    driverClassName + "'";
                logWriter.println(message);
                t.printStackTrace(logWriter);
                throw new SQLNestedException(message, t);
            }
        }

driverClassLoader为null,并且正在尝试通过Class.forName(driverClassName)加载驱动程序类。据我所知,在这种情况下,驱动程序类正在加载与BasicDataSource相同的类加载器实例。这是Standard ardClassLoader,如果我的jar在tomcat库中,它将加载该类。在我的情况下,抛出异常并使用Thread.currentThread(). getContextClassLoader(),这是WebappClassLoader实例,可以从webapp库加载类,确实如此。所以我很困惑。为什么说,如果我使用容器资源中的数据源,我必须将我的驱动程序类放在tomcat库中。

请解释,谢谢

共有1个答案

许鸿志
2023-03-14

Tomcat会自动将容器管理的连接池添加到jaxaz.sql.DataSource类型的每个资源中。提供此池的库(Commons DBCP的包重命名版本)由共享类加载器加载(在默认配置中与公共加载器相同)。池实现需要能够加载配置的JDBC驱动程序,而共享(和公共)加载程序对web应用程序类加载程序没有可见性。因此,带有JDBC驱动程序的JAR需要位于$CATALINA_BASE/lib目录中,以便可以加载它。

然而,从r754776开始,如果DBCP无法加载指定的驱动程序,它将返回到线程的上下文类加载器。如果将线程上下文类加载器设置为web应用程序的类加载者,则可以加载驱动程序。这一变化包含在DBCP 1.31.4,这意味着它包含在5.5.30以后的版本中,6.0.27,以及每一个7.0.x版本中。它也将出现在每个8.0.x版本中。

使用MarkMail对查询量进行相当不科学的观察表明,Tomcat用户邮件列表中的ClassNotFoundException问题有所减少,但这同样可能归因于人们更加意识到这个问题。

我想根本问题是这可靠吗?如果DataSource总是在线程上下文类加载器是Web应用程序类加载器时实例化,那么它将是可靠的。访问这些资源是通过JNDI,这取决于正确设置的线程上下文类加载器。如果不是这样-JNDI将无法定位Web应用程序资源。在此基础上,这应该可以工作。

全局资源(显然)仍然需要JDBC驱动程序位于$CATALINA_HOME/lib

如果< code>$CATALINA_HOME/lib和WEB-INF/lib中存在< code>JDBC驱动程序< code>JAR,可能会导致问题。如果web应用程序试图强制转换为数据库特定的对象,那么事情将会失败,因为这将是试图将由共享加载器加载的类强制转换为由web应用程序类加载器加载的同名类,这将总是失败。

所以简而言之:

  • 长期以来,不要在 WEB-INF/lib 中使用 JDBC 驱动程序的建议$CATALINA_[HOME|基地]/库支架
  • 6.0.27 开始,可以将 JDBC 驱动程序打包到 Web 应用程序中,一切仍然可以正常工作。

对于最初的错误/不完整回答,我深表歉意。这不是我第一次完全忘记自己犯下的错误,我想这也不会是最后一次。

 类似资料:
  • 问题内容: 有人告诉我,加载JDBC驱动程序的首选方法是: 我知道,这对于从XML配置文件或用户输入中读取多个驱动程序之间的动态决策更好。我很好奇的是,调用此语句如何将指定的驱动程序加载到我们什至没有将生成的“ Class”对象存储在任何地方的环境中。JavaDocs条目说: 返回与具有给定字符串名称的类或接口关联的Class对象 在那种情况下,Java开发人员仅凭此语句如何设法促进驱动程序对象的

  • 问题内容: 我在春季配置了一个netezza db。我在类路径中添加了依赖的nzjdbc.jar 春季配置: 问题答案: 将放入您的本地Maven存储库 (在该目录执行这个位于 然后像正常依赖项一样使用它: @请参阅安装第三方JAR的指南

  • 问题内容: 在进行简单的JDBC连接时,所有资源都提供相同的代码, 但是我们实际上与“ Class.forName(driver)”无关。我们没有将其存储在任何地方。它的用途是什么,因为我们与Class.forName(driver)的返回无关。 问题答案: 尝试加载命名的类。在早期的JDBC版本中,这是必需的,因为该类要求以这种方式加载该类。多年以来都不需要这样做。 忽略通话,不会发生任何不良情

  • 我正在上使用。我试图弄明白如何使用数据导入从加载数据。但我最终无法加载JDBC驱动程序类。以下是我所做的: 把放到 1.配置: 2.配置: 在

  • 我正在尝试使用本教程连接Oracle数据库。当我使用命令行:java-cp c:\jdbc-test\ojdbc6.jar;c:\jdbc-test OracleJDBC我已经将ojdbc6.jar与OracleJDBC.java放在同一个文件夹中。现在我需要在Eclipse上运行它,但它给我一个错误: 是因为OJDBC6.jar位置吗?

  • 我在为Em申明德比加载JDBC驱动程序时遇到了问题。以下是我编译和运行我的程序的案例 > 案例1: 编译:E:\java\WorkReminder Run: E:\java\WorkReminder 错误: 无法加载JDBC驱动程序org . Apache . derby . JDBC . embedded driver。请检查您的类路径。Java . lang . classnotfoundex