web-dev-qa-db-fra.com

AbstractMethodError avec le pilote JDBC jTDS sur Tomcat 8

Je déploie une application Web (WAR) sur un conteneur Web Tomcat 8.

Le WAR inclut dans le répertoire '/ WEB-INF/lib' le pilote jTDS JDBC suivant:

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

(le fichier est: jtds-1.3.1.jar).

Voici comment la ressource est définie dans 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"
/>

Dans mon code, j'obtiens le javax.sql.DataSource de la manière normale:

InitialContext cxt = new InitialContext();
if ( cxt == null ) {
    throw new RuntimeException("Uh oh -- no context!");
}
DataSource ds = (DataSource) cxt.lookup( lookupName );

Je vérifie en outre (en imprimant) que l'objet DataSource ds est du type attendu:

org.Apache.Tomcat.dbcp.dbcp2.BasicDataSource

… Mais quand j'essaye d'en sortir une connexion:

Connection conn = ds.getConnection();

… J'obtiens la trace suivante:

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)

Ce qui donne?

15

Il s'est avéré que je devais ajouter:

validationQuery="select 1"

dans la déclaration de ressources dans context.xml.

Ceci est mentionné ici (bien que mal orthographié comme validateQuery).

En creusant dans l'implémentation de JtdsConnection on voit:

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

C'est vraiment bizarre, je pense AbstractMethodError est censé être lancé uniquement par le compilateur, les méthodes non implémentées devraient lancer nsupportedOperationException . En tout cas, le code suivant de PoolableConnection montre pourquoi la présence ou non de validationQuery dans context.xml peut changer les choses. Votre validationQuery est transmis comme valeur du paramètre sqlString dans la méthode ci-dessous (ou null si vous ne définissez pas de 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;
    }
...
}

Donc, fondamentalement, si aucun validationQuery n'est présent, alors l'implémentation de la connexion de isValid est consultée, ce qui dans le cas de JtdsConnection lance bizarrement AbstractMethodError.

24

La réponse mentionnée ci-dessus par Marcus a fonctionné pour moi lorsque j'ai rencontré ce problème. Pour donner un exemple spécifique de l'apparence du paramètre validationQuery dans le fichier 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"
            />

Le paramètre validationQuery va avec chaque paramètre de pilote pour vos connexions db. Ainsi, chaque fois que vous ajoutez une autre entrée db à votre fichier context.xml, vous devrez inclure ce paramètre avec les paramètres du pilote.

4
Stephen

La réponse ci-dessus fonctionne. Si vous le configurez pour une application autonome Java, définissez la requête de validation dans la source de données.

 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
2
Gobinath Mani