Tomcat 8 上 jTDS JDBC 驱动程序的 AbstractMethodError

Posted

技术标签:

【中文标题】Tomcat 8 上 jTDS JDBC 驱动程序的 AbstractMethodError【英文标题】:AbstractMethodError with jTDS JDBC Driver on Tomcat 8 【发布时间】:2017-05-05 01:05:33 【问题描述】:

我正在将 Web 应用程序 (WAR) 部署到 Tomcat 8 Web 容器。

WAR 在 '/WEB-INF/lib' 目录中包含以下 jTDS JDBC 驱动程序:

<dependency org="net.sourceforge.jtds" name="jtds" rev="1.3.1" />

(文件为:jtds-1.3.1.jar)。

这是META-INF/context.xml中定义资源的方式:

<Resource name="jdbc/jtds/sybase/somedb"
          auth="Container"
          type="javax.sql.DataSource"
          driverClassName="net.sourceforge.jtds.jdbc.Driver"
          url="jdbc:jtds:sybase://localhost:2501/somedb"
          username="someuser" password="somepassword"
/>

在我的代码中,我以正常方式获得javax.sql.DataSource:

InitialContext cxt = new InitialContext();
if ( cxt == null ) 
    throw new RuntimeException("Uh oh -- no context!");

DataSource ds = (DataSource) cxt.lookup( lookupName );

我进一步验证(通过打印)DataSource 对象ds 是预期的类型:

org.apache.tomcat.dbcp.dbcp2.BasicDataSource

…但是当我尝试从中获得连接时:

Connection conn = ds.getConnection();

…我得到以下跟踪:

java.lang.AbstractMethodError
net.sourceforge.jtds.jdbc.JtdsConnection.isValid(JtdsConnection.java:2833)
org.apache.tomcat.dbcp.dbcp2.DelegatingConnection.isValid(DelegatingConnection.java:924)
org.apache.tomcat.dbcp.dbcp2.PoolableConnection.validate(PoolableConnection.java:282)
org.apache.tomcat.dbcp.dbcp2.PoolableConnectionFactory.validateConnection(PoolableConnectionFactory.java:359)
org.apache.tomcat.dbcp.dbcp2.BasicDataSource.validateConnectionFactory(BasicDataSource.java:2316)
org.apache.tomcat.dbcp.dbcp2.BasicDataSource.createPoolableConnectionFactory(BasicDataSource.java:2299)
org.apache.tomcat.dbcp.dbcp2.BasicDataSource.createDataSource(BasicDataSource.java:2043)
org.apache.tomcat.dbcp.dbcp2.BasicDataSource.getConnection(BasicDataSource.java:1543)

什么给了?

【问题讨论】:

【参考方案1】:

原来我必须补充:

validationQuery="select 1"

context.xml 的资源声明中。

提到了here(尽管拼写错误为validateQuery)。

深入了解JtdsConnection的实现,一看便知:

/* (non-Javadoc)
 * @see java.sql.Connection#isValid(int)
 */
public boolean isValid(int timeout) throws SQLException 
    // TODO Auto-generated method stub
    throw new AbstractMethodError();

这真的很奇怪,我认为AbstractMethodError 应该只由编译器抛出,未实现的方法应该抛出UnsupportedOperationException。无论如何,来自PoolableConnection 的以下代码说明了为什么context.xml 中的validationQuery 的存在与否可以改变事情。您的 validationQuery 在以下方法中作为 sql String 参数的值传递(如果您未定义 validationQuery,则为 null):

public void More ...validate(String sql, int timeout) throws SQLException 
    ...
    if (sql == null || sql.length() == 0) 
        ...
        if (!isValid(timeout)) 
            throw new SQLException("isValid() returned false");
        
        return;
    
...

所以基本上如果没有validationQuery 存在,那么会咨询连接自己的isValid 实现,在JtdsConnection 的情况下会奇怪地抛出AbstractMethodError

【讨论】:

我可以在 Tomcat 7/Windows 上运行该应用程序,驱动程序 1.2.8 没有问题。当我将应用程序迁移到 Docker/Linux 环境时,我遇到了这个错误。将validationQuery添加到驱动程序的conf中解决了这个问题。【参考方案2】:

以上答案有效。如果要为独立 Java 应用程序设置它,请在数据源中设置验证查询。

 BasicDataSource ds = new BasicDataSource(); 

 ds.setUsername(user);
 ds.setPassword(getPassword());
 ds.setUrl(jdbcUrl);
 ds.setDriverClassName(driver);
 ds.setMaxTotal(10);
 ds.setValidationQuery("select 1"); //DBCP throws error without this query

【讨论】:

【参考方案3】:

当我遇到这个问题时,Marcus 上面提到的答案对我有用。举一个具体的例子来说明 validationQuery 设置在 context.xml 文件中的外观:

    <Resource name="jdbc/myDB" auth="Container" type="javax.sql.DataSource"
            driverClassName="net.sourceforge.jtds.jdbc.Driver"
            url="jdbc:jtds:sqlserver://SQLSERVER01:1433/mydbname;instance=MYDBINSTANCE"
            username="dbuserid" password="dbpassword"
            validationQuery="select 1"
            />

validationQuery 设置与您的数据库连接的每个驱动程序设置一起使用。因此,每次向 context.xml 文件添加另一个 db 条目时,都需要将此设置包含在驱动程序设置中。

【讨论】:

以上是关于Tomcat 8 上 jTDS JDBC 驱动程序的 AbstractMethodError的主要内容,如果未能解决你的问题,请参考以下文章

SqlClient/OLEDB 驱动程序的连接字符串,如 jdbc:jtds 驱动程序?

ms sql microsoft的jdbc驱动和jTDS的驱动的区别

使用 JDBC 的 SQL Server 连接 - JTDS

通过 JTDS 驱动程序执行 SQL Server 调用时出现“第 24 行位置的 JDBC 转义语法无效 '=' 预期字符”错误的原因?

什么是MS SQL Server 2005 Express的jTDS JDBC Connect URL

什么相当于Microsoft JDBC中的JTDS属性?