在Tomcat 8上使用jTDS JDBC驱动出现了AbstractMethodError错误

21

我正在将一个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 );

我通过打印进一步验证,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)

出了什么问题?

3个回答

37

结果发现我必须添加:

validationQuery="select 1"

context.xml中的资源声明中。

这在这里提到(尽管拼写错误为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添加到驱动程序的配置中解决了这个问题。 - rodvlopes

7

当我遇到这个问题时,马库斯上面提到的答案对我有用。以下是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文件中添加另一个数据库条目时,都需要在驱动程序设置中包含此设置。

3
上面的答案是正确的。如果您正在为独立的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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接