sql >> データベース >  >> RDS >> Mysql

ResultSetImpl.checkColumnBoundsまたはResultSetImpl.getStringInternalで時折NullPointerExceptionが発生する

    この質問を投稿してから長い時間が経ちました。このトリッキーなNullPointerExceptionにつながった正確なシナリオを説明する回答を投稿したいと思います。 。

    これは、このような紛らわしい例外に遭遇した将来の読者が、箱の外で考えるのに役立つと思います。結局のところ、これがmysqlコネクタのバグであると疑う理由はほとんどあったからです。

    この例外を調査している間、DB接続がスレッド間で共有されておらず、同じスレッドが接続を閉じてからアクセスしようとした場合、アプリケーションがDB接続からデータを読み取ろうとしているときにDB接続を閉じることができないと確信しました。それなら、別の例外がスローされるべきでした(いくつかのSQLException )。それが、mysqlコネクタのバグを疑った主な理由でした。

    同じ接続にアクセスする2つのスレッドがあったことが判明しました 結局。これを理解するのが難しい理由は、これらのスレッドの1つがガベージコレクタスレッドであったためです。 。

    投稿したコードに戻ります:

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

    問題は、「同じ接続を使用してDBから他のレコードをロードする処理を実行する」セクションにあります。残念ながら、問題があるとは思わなかったため、元の質問には含めませんでした。

    そのセクションを拡大すると、次のようになります。

    if (sc != null) {
        ...
        someMethod (conn);
        ...
    }
    

    そしてsomeMethod 次のようになります:

    public void someMethod (Connection conn) 
    {
        ...
        SomeOtherClass instance = new SomeOtherClass (conn);
        ...
    }
    

    SomeOtherClass このように見えます(もちろん、ここでは簡略化しています):

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

    SomeOtherClass 一部のシナリオでは独自のDB接続を作成できますが、ここにあるような他のシナリオでは既存の接続を受け入れることができます。

    ご覧のとおり、そのセクションにはsomeMethodの呼び出しが含まれています オープン接続を引数として受け入れます。 someMethod SomeOtherClassのローカルインスタンスに接続を渡します 。 SomeOtherClass finalizeがありました 接続を閉じるメソッド。

    さて、someMethodの後 戻り値、instance ガベージコレクションの対象になります。ガベージコレクションされると、そのfinalize メソッドは、接続を閉じるガベージコレクタスレッドによって呼び出されます。

    ここで、forループに戻ります。このループは、ガベージコレクタスレッドによっていつでも閉じられる可能性のある同じ接続を使用してSELECTステートメントを実行し続けます。

    アプリケーションスレッドが開いている接続に依存するmysqlコネクタメソッドの途中にあるときに、ガベージコレクタスレッドがたまたま接続を閉じた場合、NullPointerException 発生する可能性があります。

    finalizeを削除する メソッドが問題を解決しました。

    finalizeをオーバーライドすることはあまりありません クラスのメソッドであるため、バグを見つけるのが非常に困難でした。



    1. Nodejsは、私が期待することを行わないことを表明し、約束します

    2. ディレクトリ内のファイルのリストを見つける際の問題

    3. json列と複数の列

    4. WindowsAPI関数CreateProcessAを使用してmysqlを初期化します