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

Come gestire correttamente i deadlock di InnoDB in Java/JDBC?

Il tuo codice è essenzialmente corretto. L'eccezione sollevata quando si verifica un dead lock è una SQLException . L'eccezione è getSQLState() il metodo fornisce restituisce un codice di errore che fornisce informazioni aggiuntive sull'errore effettivo.

Dovresti anche attendere un breve lasso di tempo tra i tentativi, in modo da non caricare troppo il tuo server.

Come hai abilmente intuito, imposta un numero massimo di tentativi, o potresti finire in un ciclo infinito.

Il codice finale potrebbe assomigliare a questo:

boolean oops;
int retries = 5;
Connection c = null;
Statement s = null;
ResultSet rs = null;    

do
{
    oops = false;
    c = null;
    s = null;
    rs = null;
    try
    {
        c = openConnection();
        s = c.createStatement();
        rs = s.executeQuery("SELECT stuff FROM mytable");
        fiddleWith(rs);
    }
    catch (SQLException sqlex)
    {
        oops = true;
        switch(sqlex.getErrorCode()())
        {
            case MysqlErrorNumbers.ER_LOCK_DEADLOCK:
                // deadlock or lock-wait time-out occured
                break;
            ...
        }
        Thread.sleep(1000); // short delay before retry
    }
    finally
    {
        if (rs != null) try {
            rs.close();
        } catch (SQLException e) {
            // some error handler here
        }

        if (s != null) try {
            s.close();
        } catch (SQLException e) {
            // some error handler here
        }

        if (c != null) try {
            c.close();
        } catch (SQLException e) {
            // some error handler here
        }

    }
}
while (oops == true && retries-- > 0);

Ovviamente il codice sopra è sub ottimale. Potresti voler differenziare gli errori che si verificano al momento della connessione e gli errori al momento dell'esecuzione. Potresti anche rilevare che dopo alcuni errori, ci sono poche speranze che un altro tentativo funzioni (ad es. credenziali errate o errore di sintassi SQL).

Hai fatto molte domande, ma cercherò di rispondere a tutte:

Sì, vedi sopra:SQLException Sono quelli, con maggiori informazioni fornite da getErrorCode() o getSQLState() .

Una SQLException potrebbe essere lanciato praticamente da tutti i metodi di tutte le classi da java.sql pacchetto.

Sì, vedi sopra.

Ovviamente non devi ricreare un PreparedStatement tra due interrogazioni. Devi solo impostare nuovi valori per i tuoi parametri prima di chiamare executeQuery() ancora. Ovviamente se devi eseguire un'altra query, allora un nuovo PreparedStatement è richiesto.

Un (nuovo) ResultSet l'oggetto viene restituito da Statement.executeQuery() , che rappresenta il risultato della query. Non crei mai un oggetto del genere da solo. Idealmente chiamerai ResultSet.close() il prima possibile per liberare la memoria.

Ti consiglio vivamente di seguire il secondo capitolo di questo tutorial ("Elaborazione delle istruzioni SQL").