javajdbcconnection-poolingtomcat8connector-j

Method com/mysql/jdbc/PreparedStatement.isClosed()Z is abstract


I'm trying to change the connection pool of my app, in order to use Tomcat's connection pool (org.apache.tomcat.jdbc.pool) instead of "Apache Commons DBCP".

However, I'm getting this error when trying to connect to the DB:

javax.servlet.ServletException: java.lang.AbstractMethodError: Method com/mysql/jdbc/PreparedStatement.isClosed()Z is abstract
org.apache.jasper.runtime.PageContextImpl.doHandlePageException(PageContextImpl.java:909)
org.apache.jasper.runtime.PageContextImpl.handlePageException(PageContextImpl.java:838)
...
...

I've read in other links that normally this is a problem with the MySQL-JDBC driver version, however, I've just updated to the latest Connector/J version (mysql-connector-java-8.0.11.jar) but I'm still getting this error.

Here's how the connection pool is created:

First, this goes on the context.xml file in the META-INF directory of my app:

<?xml version="1.0" encoding="UTF-8"?>

<Context>
<Resource
    name="rhwebDB"
    auth="Container"
    type="javax.sql.DataSource"
    factory="org.apache.tomcat.jdbc.pool.DataSourceFactory"
    testWhileIdle="true"
    testOnBorrow="true"
    testOnReturn="false"
    validationQuery="SELECT 1"
    validationInterval="30000"
    timeBetweenEvictionRunsMillis="30000"
    maxActive="10"
    minIdle="5"
    maxIdle="10"
    maxWait="10000"
    initialSize="2"
    removeAbandonedTimeout="60"
    removeAbandoned="true"
    logAbandoned="true"
    minEvictableIdleTimeMillis="30000"              
    username="dbUser"
    password="dbPwd"
    driverClassName="com.mysql.jdbc.Driver"
    url="jdbc:mysql://127.0.0.1:3306/rhweb2015"/>
</Context>

Then I have a DBUtil.class that all the other libraries use:

public class DBUtil {

    static Connection connection = null;
    static {
        try {
            Context context = new InitialContext();
            DataSource ds = (DataSource)context.lookup("java:comp/env/rhwebDB");
            connection = ds.getConnection();
        } catch (NamingException e) {
            System.out.println("DBUtil.NamingException" + e);
        } catch (SQLException e) {
            System.out.println("DBUtil.SQLException" + e);
        }
    }

    public static Connection getConnection() {
        return connection;
    }

    public static synchronized void closeConnection(Connection conn) {
        try {
            if (conn != null && !conn.isClosed())
                conn.close();
        } catch (SQLException sqle) {
            System.out.println("Error closing the connection ! " + sqle);
        }

    }
}

And finally, all the other java libraries use the connection pool like this:

public boolean someFunction( String myValue ){
    Connection conn = null;
    boolean fRetVal = false;

    String query = "select something from anytable";

    try {
        conn = DBUtil.getConnection();
        Statement stmt = conn.createStatement();
        ResultSet rs = stmt.executeQuery( query );

        if ( rs.next() )
            fRetVal = true;

        rs.close();
        stmt.close();

    } catch( SQLException ex ) {
            System.out.println(ex);
    }finally{
        DBUtil.closeConnection(conn);
    }

    return fRetVal;
}

Am I missing something? I don't get any errors when Tomcat starts.

JDK version: 8 (java version "1.8.0_111") Tomcat version: 8.5.8 MySQL Server 5.6

Any help will be really appreciated


Solution

  • This is all wrong. You are keeping a dog and barking yourself. You can't use static Connections in the first place, and in the second place using a static Connection defeats the entire purpose of using a connection pool. It should be more like this:

    public class DBUtil {
    
        static DataSource ds;
        static {
            try {
                Context context = new InitialContext();
                ds = (DataSource)context.lookup("java:comp/env/rhwebDB");
            } catch (NamingException e) {
                System.out.println("DBUtil.NamingException" + e);
            } catch (SQLException e) {
                System.out.println("DBUtil.SQLException" + e);
            }
        }
    
        public static Connection getConnection() throws SQLException {
            return ds.getConnection();
        }
    }
    

    and, using try-with-resources to close everything:

    public boolean someFunction( String myValue ){
        boolean fRetVal = false;
    
        String query = "select something from anytable";
    
        try (Connection conn = DBUtil.getConnection();
            Statement stmt = conn.createStatement();
            ResultSet rs = stmt.executeQuery( query )) {
            if ( rs.next() )
                fRetVal = true;
        } catch( SQLException ex ) {
            System.out.println(ex);
        }
    
        return fRetVal;
    }
    

    E&OE

    But note that you don't really need the DBUtil class at all. You can inject the DataSource anywhere you need it via an annotation.