Mysql
 sql >> Base de Dados >  >> RDS >> Mysql

Como lidar adequadamente com os deadlocks do InnoDB em Java/JDBC?


Seu código está essencialmente correto. A exceção gerada quando ocorre um dead lock é uma SQLException . O getSQLState() da exceção O método fornece retorna um código de erro que fornece informações adicionais sobre o erro real.

Você também deve esperar um curto período de tempo entre as tentativas, para não carregar muito seu servidor.

Como você adivinhou, defina um número máximo de tentativas, ou você pode acabar em um loop infinito.

O código final poderia ficar assim:
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);

Obviamente, o código acima é sub-ótimo. Você pode querer diferenciar os erros que ocorrem no momento da conexão e os erros no momento da execução. Você também pode detectar que, após alguns erros, há pouca esperança de que outra tentativa funcione (por exemplo, credenciais erradas ou erro de sintaxe SQL).

Você fez muitas perguntas, mas vou tentar responder a todas:

Sim, veja acima:SQLException 's são os únicos, com mais informações fornecidas por getErrorCode() ou getSQLState() .

Uma SQLException poderia ser lançado por praticamente todos os métodos de todas as classes do java.sql pacote.

Sim, veja acima.

Obviamente você não deve recriar um PreparedStatement entre duas consultas. Você só precisa definir novos valores para seus parâmetros antes de chamar executeQuery() novamente. Claro que se você precisar executar outra consulta, então um novo PreparedStatement É necessário.

Um (novo) ResultSet objeto é retornado por Statement.executeQuery() , que representa o resultado da consulta. Você nunca cria tal objeto sozinho. Idealmente, você chamará ResultSet.close() o mais rápido possível para liberar a memória.

Eu recomendo fortemente que você siga o segundo capítulo este tutorial ("Processando Instruções SQL").