sql >> Database teknologi >  >> RDS >> Mysql

Lejlighedsvis NullPointerException i ResultSetImpl.checkColumnBounds eller ResultSetImpl.getStringInternal

Det er længe siden, jeg postede dette spørgsmål, og jeg vil gerne sende et svar, der beskriver det nøjagtige scenarie, der førte til denne vanskelige NullPointerException .

Jeg tror, ​​at dette kan hjælpe fremtidige læsere, der støder på sådan en forvirrende undtagelse, til at tænke ud af boksen, da jeg havde næsten al mulig grund til at antage, at dette var en mysql-forbindelsesfejl, selvom det alligevel ikke var det.

Mens jeg undersøgte denne undtagelse, var jeg sikker på, at min applikation umuligt kunne lukke DB-forbindelsen, mens jeg forsøgte at læse data fra den, da mine DB-forbindelser ikke deles på tværs af tråde, og hvis den samme tråd lukkede forbindelsen og derefter forsøgte at få adgang det, skulle en anden undtagelse være blevet kastet (noget SQLException ). Det var hovedårsagen til, at jeg havde mistanke om en mysql-forbindelsesfejl.

Det viste sig, at der var to tråde, der fik adgang til den samme forbindelse trods alt. Grunden til, at det var svært at finde ud af, var, at en af ​​disse tråde var en garbage collector-tråd .

Går tilbage til koden, jeg har sendt:

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

Problemet ligger i afsnittet "udfør noget behandling, der involverer indlæsning af andre poster fra DB'en ved hjælp af den samme forbindelse", som jeg desværre ikke inkluderede i mit oprindelige spørgsmål, da jeg ikke troede, problemet var der.

Zoomer vi ind på det afsnit, har vi:

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

Og someMethod ser sådan ud:

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

SomeOtherClass ser sådan ud (selvfølgelig forenkler jeg her):

public class SomeOtherClass
{
    Connection conn;

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

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

}

SomeOtherClass kan oprette sin egen DB-forbindelse i nogle scenarier, men kan acceptere en eksisterende forbindelse i andre scenarier, som den vi har her.

Som du kan se, indeholder denne sektion et opkald til someMethod der accepterer den åbne forbindelse som argument. someMethod sender forbindelsen til en lokal forekomst af SomeOtherClass . SomeOtherClass havde en finalize metode, der lukker forbindelsen.

Nu, efter someMethod returnerer, instance bliver berettiget til renovation. Når det samles affald, bliver det finalize metode kaldes af garbage collector-tråden, som lukker forbindelsen.

Nu vender vi tilbage til for-løkken, som fortsætter med at udføre SELECT-sætninger ved hjælp af den samme forbindelse, som til enhver tid kan lukkes af garbage collector-tråden.

Hvis garbage collector-tråden tilfældigvis lukker forbindelsen, mens applikationstråden er midt i en eller anden mysql-forbindelsesmetode, der er afhængig af, at forbindelsen er åben, vises en NullPointerException kan forekomme.

Fjerner finalize metode løste problemet.

Vi tilsidesætter ikke ofte finalize metode i vores klasser, hvilket gjorde det meget vanskeligt at lokalisere fejlen.



  1. Hvordan kontrollerer man, om en MySQL-forespørgsel ved hjælp af den ældre API var vellykket?

  2. KRYDS/YDRE ANVENDELSE i MySQL

  3. Hvordan last_insert_rowid() virker i SQLite

  4. MySQL lagrede procedurer