首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >通过资源加载jdbc驱动程序(Tomcat 7)

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

Stack Overflow用户
提问于 2013-10-17 15:35:20
回答 1查看 4.8K关注 0票数 2

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

代码语言:javascript
复制
<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>

net.sf.log4jdbc.DriverSpy是在log4jdbc4-1.2.jar中定义的,该类放在我的应用程序库文件夹中。对我来说也很好。但是这里据说,带驱动程序类的jar只应该放在tomcat文件夹中。

Tomcat使用它的BasicDataSource类加载驱动程序:

代码语言:javascript
复制
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相同的类加载器实例加载的。这是StandardClassLoader,如果我的jar是tomcat,它将加载这个类。在我的示例中,会抛出异常并使用Thread.currentThread().getContextClassLoader(),它是WebappClassLoader实例,可以从webapp库加载类,并且可以加载类。所以我很困惑。为什么说,如果我使用容器资源中的数据源,就必须将我的驱动程序类放在tomcat库中。

请解释一下,谢谢

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2013-10-17 15:43:11

Tomcat自动将容器托管连接池添加到jaxaz.sql.DataSource类型的每个资源中。提供此池的库( Commons的包重命名版本)由共享类加载器(在默认配置中与公共加载程序相同)加载。池实现需要能够加载配置好的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问题有所减少,但同样可能是因为人们对这个问题有更多的了解。

我想最基本的问题是这可靠吗?如果当线程上下文类加载器是web应用程序类加载器时,DataSource总是被实例化,那么它将是可靠的。对这些资源的访问是通过JNDI进行的,这取决于正确设置线程上下文类加载器。如果不是,JNDI将无法找到web应用程序资源。在此基础上,这应该是可行的。

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

如果JDBC驱动程序JAR存在于$CATALINA_HOME/lib and WEB-INF/lib中,则可能会导致问题。如果web应用程序试图转换到特定于数据库的对象,那么就会失败,因为这将是尝试将由共享加载器加载的类转换为web应用程序类加载器加载的同名类,而该类总是会失败。

因此,简而言之:

  • 长期建议不要在WEB-INF/lib$CATALINA_[HOME|BASE]/lib中使用JDBC驱动程序。
  • 6.0.27开始,可以将JDBC驱动程序打包到web应用程序中,而且一切都将继续工作。

为最初的错误/不完整的答案道歉。这不是我第一次完全忘记我所做的承诺,我怀疑这不会是最后一次。

票数 6
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/19431102

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档