【问题标题】:Method com/mysql/jdbc/PreparedStatement.isClosed()Z is abstract方法 com/mysql/jdbc/PreparedStatement.isClosed()Z 是抽象的
【发布时间】:2018-04-25 22:56:12
【问题描述】:

我正在尝试更改我的应用程序的连接池,以便使用 Tomcat 的连接池 (org.apache.tomcat.jdbc.pool) 而不是“Apache Commons DBCP”。

但是,我在尝试连接数据库时遇到此错误:

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)
...
...

我在其他链接中读到这通常是 MySQL-JDBC 驱动程序版本的问题,但是,我刚刚更新到最新的 Connector/J 版本 (mysql-connector-java-8.0.11.jar ) 但我仍然收到此错误。

连接池的创建方式如下:

首先,这是在我的应用的 META-INF 目录中的 context.xml 文件中:

<?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>

然后我有一个所有其他库都使用的 DBUtil.class:

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);
        }

    }
}

最后,所有其他 java 库都像这样使用连接池:

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;
}

我错过了什么吗? Tomcat启动时我没有收到任何错误。

JDK 版本:8(java 版本“1.8.0_111”) Tomcat版本:8.5.8 MySQL 服务器 5.6

任何帮助将不胜感激

【问题讨论】:

  • 您对如何使用连接池的概念完全错误。完全摆脱你的 DBUtil 类,特别是它的静态 Connection 对象; 每次请求时都使用池中的连接;并通过关闭它将其返回到池中。你养了一只狗,你自己狂吠。
  • 如果我摆脱了DBUtil类,连接池将如何创建?在该类中,它指定了连接池信息的定义位置:DataSource ds = (DataSource)context.lookup("java:comp/env/rhwebDB");
  • 我的意思是,如何从池中获取新连接?我应该在每个使用连接池的函数上指定所有数据源代码吗?有很多使用它的功能。我有点迷路了。
  • 好的,看我的回答。
  • 错误本身意味着您使用的是非常旧版本的 MySQL Connector/J 驱动程序。

标签: java jdbc connection-pooling tomcat8 connector-j


【解决方案1】:

这都是错误的。你养了一只狗,你自己狂吠。首先,您不能使用静态Connections,其次,使用静态Connection 会破坏使用连接池的全部目的。它应该更像这样:

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();
    }
}

并且,使用 try-with-resources 关闭所有内容:

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;
}

电子与工程

但请注意,您根本不需要 DBUtil 类。你可以通过注解在任何你需要的地方注入DataSource

【讨论】:

  • 非常感谢!!这些天我似乎无法想清楚。如果你也不介意回答这个问题,你为什么声明static 是返回连接的方法? public static Connection getConnection() throws SQLException { return ds.getConnection(); }
  • 因为你做到了。没有实例状态,那么为什么要让它成为非静态的呢?或者,您可以将DataSource 设为非静态,在构造函数而不是静态初始化程序中构造它,并使getConnection() 非静态,然后将整个东西变成单例......但我不真的明白这一点。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-12-15
  • 1970-01-01
  • 2012-09-21
  • 1970-01-01
  • 2014-06-20
  • 2014-01-16
  • 1970-01-01
相关资源
最近更新 更多