Tomcat 8 上的 jTDS JDBC 驱动程序出现 AbstractMethodError

AbstractMethodError with jTDS JDBC Driver on Tomcat 8

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

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)

什么给了?

结果我不得不添加:

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 is supposedly thrown by the compiler only, unimplemented methods ought to throw UnsupportedOperationException. At any rate, the following code from PoolableConnection 说明了为什么 context.xml 中是否存在 validationQuery 可以改变事情。您的 validationQuery 在下面的方法中作为 sql String 参数的值传递(或者 null 如果您没有定义 validationQuery):

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.

以上答案有效。如果您为独立 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

当我遇到这个问题时,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 文件时,您都需要将此设置包含在驱动程序设置中。