Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/369.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java ResultSetTimepl.checkColumnBounds或ResultSetTimepl.getStringInternal中偶尔出现NullPointerException_Java_Mysql_Jdbc - Fatal编程技术网

Java ResultSetTimepl.checkColumnBounds或ResultSetTimepl.getStringInternal中偶尔出现NullPointerException

Java ResultSetTimepl.checkColumnBounds或ResultSetTimepl.getStringInternal中偶尔出现NullPointerException,java,mysql,jdbc,Java,Mysql,Jdbc,首先,请不要将此关闭为与NullPointerException及其修复方法重复的内容。我知道什么是NullPointerException,我知道如何在我自己的代码中解决它,但当mysql-connector-java-5.1.36-bin.jar抛出它时就不知道了,我无法控制它 我们在mySQL数据库上运行公共数据库查询时遇到了异常,该查询大部分时间都有效。我们在部署新版本后开始看到此异常,但发生此异常的查询在很长时间内没有更改 下面是查询的样子(经过一些必要的简化)。我用前后执行的一些逻辑

首先,请不要将此关闭为与
NullPointerException
及其修复方法重复的内容。我知道什么是
NullPointerException
,我知道如何在我自己的代码中解决它,但当mysql-connector-java-5.1.36-bin.jar抛出它时就不知道了,我无法控制它

我们在mySQL数据库上运行公共数据库查询时遇到了异常,该查询大部分时间都有效。我们在部署新版本后开始看到此异常,但发生此异常的查询在很长时间内没有更改

下面是查询的样子(经过一些必要的简化)。我用前后执行的一些逻辑来包围它。实际的代码并不都在一个方法中,但我将其放在一个块中以使其更易于理解

Connection conn = ... // the connection is open
...
for (String someID : someIDs) {
    SomeClass sc = null;
    PreparedStatement
        stmt = conn.prepareStatement ("SELECT A, B, C, D, E, F, G, H FROM T WHERE A = ?");
    stmt.setString (1, "someID");
    ResultSet res = stmt.executeQuery ();
    if (res.next ()) {
        sc = new SomeClass ();
        sc.setA (res.getString (1));
        sc.setB (res.getString (2));
        sc.setC (res.getString (3));
        sc.setD (res.getString (4));
        sc.setE (res.getString (5));
        sc.setF (res.getInt (6));
        sc.setG (res.getString (7));
        sc.setH (res.getByte (8)); // the exception is thrown here
    }
    stmt.close ();
    conn.commit ();
    if (sc != null) {
        // do some processing that involves loading other records from the
        // DB using the same connection
    }
}
conn.close();
res.getByte(8)
导致具有以下调用堆栈的
NullPointerException

com.mysql.jdbc.ResultSetImpl.checkColumnBounds(ResultSetImpl.java:763) com.mysql.jdbc.ResultSetImpl.getStringInternal(ResultSetImpl.java:5251) com.mysql.jdbc.ResultSetImpl.getString(ResultSetImpl.java:5173) com.mysql.jdbc.ResultSetImpl.getByte(ResultSetImpl.java:1650) org.apache.tomcat.dbcp.dbcp2.DelegatingResultSet.getByte(DelegatingResultSet.java:206) org.apache.tomcat.dbcp.dbcp2.DelegatingResultSet.getByte(DelegatingResultSet.java:206)

我搜索了相关mysql连接器版本的源代码,发现了以下内容(摘自):

这意味着
this.fields
不知何故变成了
null

我能找到的最接近的东西是,它没有答案

我怀疑问题不在我发布的查询中。可能是由于我们在同一连接上运行的一些其他语句,
连接
实例出了问题。我所能说的是,我们在执行每个语句之后立即关闭它,并从它的
结果集
读取数据

编辑(2017年1月19日):

我无法在我的开发环境中重新创建错误。我想可能是长时间使用同一个连接时触发了mysql连接器错误。我将上述循环限制为一次最多加载6个元素。此外,我们将mysql连接器版本升级到5.1.40

我们仍然在
ResultSetImpl
中看到
NullPointerException
s,但这次是在不同的位置

堆栈跟踪是:

com.mysql.jdbc.ResultSetImpl.getStringInternal(ResultSetImpl.java:5294) com.mysql.jdbc.ResultSetImpl.getString(ResultSetImpl.java:5151) org.apache.tomcat.dbcp.dbcp2.DelegatingResultSet.getString(DelegatingResultSet.java:198) org.apache.tomcat.dbcp.dbcp2.DelegatingResultSet.getString(DelegatingResultSet.java:198)

这意味着这次异常是由于我们的一个
res.getString()
调用引发的(我不知道是哪一个)

我找到了mysql-connector-java-5.1.40-bin.jar的源代码,相关代码是:

5292            // Handles timezone conversion and zero-date behavior
5293
5294            if (checkDateTypes && !this.connection.getNoDatetimeStringSync()) {
5295                switch (metadata.getSQLType()) {
这意味着
此连接
为空
this.connection
是类型为
MySQLConnection
的实例变量,它在
ResultSetImpl
的构造函数中初始化,只有在调用
public void realClose(boolean calledeplicity)
时才设置为null(由
public void close()调用)
,根据源代码中的文档,在调用
ResultSet.close()
时调用它)。我们绝对不会在读取所有数据之前关闭
结果集


有什么想法可以继续吗?

您可以重写代码以使用一个try-catch块吗? 然后,您将在方法中拥有该连接,其他人无法关闭该连接

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

public class StackProblem1
{
    void dbQuery(final String[] someIDs)
    {
        try (final Connection conn = getConnection();
             final PreparedStatement stmt = conn.prepareStatement(
                 "SELECT A, B, C, D, E, F, G, H FROM T WHERE A = ?"))
        {
            for (final String someID : someIDs)
            {
                stmt.setString(1, "someID");
                final ResultSet res = stmt.executeQuery();
                if (res.next())
                {
                    final SomeClass sc = new SomeClass();
                    sc.set(res.getString(1));
                    sc.set(res.getString(2));
                    sc.set(res.getString(3));
                    sc.set(res.getString(4));
                    sc.set(res.getString(5));
                    sc.set(res.getInt(6));
                    sc.set(res.getString(7));
                    sc.set(res.getByte(8)); // the exception is thrown here
                    // do some processing that involves loading other records from the
                    // DB using the same connection
                }
            }
        }
        catch (final SQLException sqlEx)
        {
            sqlEx.printStackTrace();
        }
    }

    /**
     * @return the connection is open
     */
    private Connection getConnection()
    {
        return null;//FIXME return connection
    }
}

我无法证明这是正确的解释,但即使不是,它也可能指向一些好的方向

归根结底,我们要弄清楚
字段
受保护的成员变量是如何取
null
值的

如果我正确地跟踪了堆栈跟踪,那么ResultSetImpl将通过调用static来实例化,static由which调用,which由which调用 在getResultSet()中,我们发现第一个
字段初始化为
null

Field[] fields = null;
然后就有了

if (metadataFromCache == null) {
    fields = new Field[(int) columnCount];
    ...
} else {
    for (int i = 0; i < columnCount; i++) {
        skipPacket();
    }
}
true
usingCursor
也是
true
,也就是说
versionmeetsmimum(5,0,5)&&(this.serverStatus&SERVER\u STATUS\u CURSOR\u存在)!=0
也是
true
那么打电话的时候

ResultSetImpl rs = buildResultSetWithRows(callingStatement, catalog, fields, rows, resultSetType, resultSetConcurrency, isBinaryEncoded)
字段将为
null

这可能导致
ResultSetImpl
在其
字段中获得
null
值,并且与从5.0.5之前的版本升级到5.1.36之后发生的情况兼容

坏消息是,我看不出
isbinarycoded
如何将值设为true,这是使用
null
字段创建
ResultSetImpl
实例的另一个必要条件

如果这个推测是正确的,那么这个bug是一个缺失的
(metadataFromCache==null)?字段:metadataFromCache
位于
MysqlIO.getResultSet()
并将
ResultSet
类型从
type\u FORWARD\u ONLY
更改为
type\u SCROLL\u Unsensitive
可能会阻止
NullPointerException

就我所知,这一切发生的唯一途径是 有人/某事正在调用ResultSet.close() 已调用ResultSet.getString(),但尚未返回

这可能是您的应用程序(它是多线程的,还是有 一个棘手的处理路径),或者你可能会失去连接 在这段时间的某个时候,这会导致驾驶员关闭 隐式连接,关闭所有打开的语句,关闭 全部开放结果se
if (metadataFromCache == null) {
    fields = new Field[(int) columnCount];
    ...
} else {
    for (int i = 0; i < columnCount; i++) {
        skipPacket();
    }
}
this.connection.versionMeetsMinimum(5, 0, 2) &&
this.connection.getUseCursorFetch() &&
isBinaryEncoded &&
callingStatement != null &&
callingStatement.getFetchSize() != 0 &&
callingStatement.getResultSetType() == ResultSet.TYPE_FORWARD_ONLY
ResultSetImpl rs = buildResultSetWithRows(callingStatement, catalog, fields, rows, resultSetType, resultSetConcurrency, isBinaryEncoded)
Connection conn = ... // the connection is open
...
    SomeClass sc = null;
    PreparedStatement
        stmt = conn.prepareStatement ("SELECT A, B, C, D, E, F, G, H FROM T WHERE A in (?)"); 
//here you need to concate String to form like ('a','b')
        stmt.setString (1, someID);
        ResultSet res = stmt.executeQuery ();
        if (res.next ()) {
            sc = new SomeClass ();
            sc.setA (res.getString (1));
            sc.setB (res.getString (2));
            sc.setC (res.getString (3));
            sc.setD (res.getString (4));
            sc.setE (res.getString (5));
            sc.setF (res.getInt (6));
            sc.setG (res.getString (7));
            sc.setH (res.getByte (8)); 
        }
        stmt.close ();
        conn.commit ();
        if (sc != null) {
            // do some processing that involves loading other records from the
            // DB using the same connection
        }

    conn.close();
Connection conn = ... // the connection is open
...
for (String someID : someIDs) {
    SomeClass sc = null;
    PreparedStatement
        stmt = conn.prepareStatement ("SELECT A, B, C, D, E, F, G, H FROM T WHERE A = ?");
    stmt.setString (1, "someID");
    ResultSet res = stmt.executeQuery ();
    if (res.next ()) {
        sc = new SomeClass ();
        sc.setA (res.getString (1));
        sc.setB (res.getString (2));
        sc.setC (res.getString (3));
        sc.setD (res.getString (4));
        sc.setE (res.getString (5));
        sc.setF (res.getInt (6));
        sc.setG (res.getString (7));
        sc.setH (res.getByte (8)); // the exception is thrown here
    }
    stmt.close ();
    conn.commit ();
    if (sc != null) {
        // do some processing that involves loading other records from the
        // DB using the same connection
    }
}
conn.close();
if (sc != null) {
    ...
    someMethod (conn);
    ...
}
public void someMethod (Connection conn) 
{
    ...
    SomeOtherClass instance = new SomeOtherClass (conn);
    ...
}
public class SomeOtherClass
{
    Connection conn;

    public SomeOtherClass (Connection conn) 
    {
        this.conn = conn;
    }

    protected void finalize() throws Throwable
    { 
        if (this.conn != null)
            conn.close();
    }

}