Mysql
 sql >> база данни >  >> RDS >> Mysql

Случайно изключение на NullPointerException в ResultSetImpl.checkColumnBounds или ResultSetImpl.getStringInternal

Измина много време, откакто публикувах този въпрос и искам да публикувам отговор, който описва точния сценарий, довел до това сложно NullPointerException .

Мисля, че това може да помогне на бъдещите читатели, които се сблъскат с такова объркващо изключение, да мислят извън кутията, тъй като имах почти всички основания да подозирам, че това е грешка в mysql конектора, въпреки че в крайна сметка не беше.

Докато разследвах това изключение, бях сигурен, че приложението ми не може да затваря връзката с DB, докато се опитва да чете данни от нея, тъй като моите DB връзки не се споделят между нишки и ако същата нишка затвори връзката и след това се опита да получи достъп би трябвало да бъде изведено различно изключение (някакво SQLException ). Това беше основната причина да подозирам грешка в конектора на 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();

Проблемът се крие в секцията „извършете някаква обработка, която включва зареждане на други записи от 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. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Как да получите идентификатора на последния вмъкнат ред, използвайки readystatement?

  2. Как да използвам израз IF в заявка за присъединяване към MySQL?

  3. AWS Aurora:MySQL сървърът работи с опцията --read-only, така че не може да изпълни тази инструкция

  4. MySQL най-добрият начин за съхранение на дълги низове

  5. „pip install MySQL-python“ се проваля с „IndexError“