2009-10-08 10 views
12

mam przeżywa kilka błędów aplikacji na szynach, wzdłuż linii:W jakich okolicznościach chcesz Szyny należy ustawić NIE ponownie połączyć się z MySQL

ActiveRecord::StatementInvalid: Mysql::Error: Lost connection to MySQL server during query: SELECT * FROM `actions` WHERE (`foo`.`id` = 16) 

Co wydaje się dzieje, że mysql połączenie jest zamykane po przekroczeniu limitu czasu, a szyny nie zauważają, dopóki nie jest za późno.

remedies I findappear to be ustawić flagę ponownie połączyć się z prawdą w database.yaml lub do jakiegokolwiek działania bazy dodanie kodu tak:

def some_database_operation 
    begin 
    Account.find(1) 
    # or some other database operations here... 
    rescue ActiveRecord::StatementInvalid 
    ActiveRecord::Base.connection.reconnect! 
    unless @already_retried 
     @already_retried = true 
     retry 
    end 
    raise 
    else 
    @already_retried = false 
    end 
end 
end 

Jestem wymieniając tę ​​opcję over this one visible here, ponieważ opcja ta jest najwyraźniej niebezpieczne dla transakcji:

ActiveRecord::ConnectionAdapters::MysqlAdapter.module_eval do 
    def execute_with_retry_once(sql, name = nil) 
    retried = false 
    begin 
     execute_without_retry_once(sql, name) 
    rescue ActiveRecord::StatementInvalid => exception 
     ActiveRecord::Base.logger.info "#{exception}, retried? #{retried}" 

     # Our database connection has gone away, reconnect and retry this method 
     reconnect! 
     unless retried 
     retried = true 
     retry 
     end 
    end 
    end 

    alias_method_chain :execute, :retry_once 
end 

z opcji, aby uniknąć ten przykry błąd, opcja reconnect w pliku YAML wydaje przez zdecydowanie tidiest opcji - ale jestem ciekawy; dlaczego nie ustawisz domyślnie tej wartości w bazie danych?

Wolę nie rozwiązywać jednego problemu, powodując obciążenie innych w dalszej linii.

Dzięki,

Odpowiedz

12

Jak wskazano w pytaniu, jeden możliwy efekt uboczny automatycznie ponownym (jeśli odbywa się na poziomie poszczególnych rachunku), jest to, że nie jest to transakcja bezpieczna.

MySQL documentation w rzeczywistości wyraźnie stwierdza, że ​​funkcja auto-reconnect dotyczy transakcji:

Wszelkie czynne transakcje są wycofywane i tryb AUTOCOMMIT jest zresetowane.

Aplikacje, które nie zostały napisane, aby sobie z tym poradzić, mogą łatwo ulec uszkodzeniu. Dokumentacja zawiera również listę innych efektów ubocznych spowodowanych funkcją automatycznego ponownego nawiązywania połączenia, które mogą spowodować, że aplikacje nie zostaną napisane, aby przewidzieć, że zachowanie będzie działać nieprawidłowo lub ulegnie awarii.

Ponadto, jeśli połączenie z bazą danych zostało nagle przerwane, serwer nie może poprawnie zwolnić blokady, które są utrzymywane przez połączenia, tak to brzmi jak aplikacja mogła impasu w niektórych przypadkach:

Jeśli połączenie zostanie przerwane, możliwe, że sesja powiązana z połączeniem po stronie serwera będzie nadal działać, jeśli serwer nie wykrył jeszcze, że klient nie jest już połączony. W takim przypadku, wszystkie blokady przechowywane przez oryginalne połączenie nadal należą do tej sesji , więc możesz chcieć zabić ją przez wywoływanie mysql_kill().

+2

OK, teraz jestem całkowicie zdezorientowany. To sugeruje, że ustawienie 'reconnect' na' true' może być szkodliwe, ponieważ transakcje wycofywane, gdy nie są przypuszczane, brzmią jak coś złego. Jakie jest zwykle obejście, aby uniknąć tego stanu rzeczy? –

+0

Rozwiązaniem jest upewnienie się, że twoje transakcje są "atomowe" - to znaczy, że w przypadku utraty połączenia i ponownego połączenia, cała transakcja powinna zostać ponowiona, a nie tylko pojedyncze oświadczenie w ramach transakcji. Nie jestem pewien, jak to działa w Railsach, ale myślę, że jednym z rozwiązań byłoby umieszczenie transakcji w procedurze przechowywanej - w kodzie Railsowym wykonuje się pojedynczą instrukcję SQL, aby uruchomić procedurę przechowywaną, a następnie, jeśli automatycznie się ponownie łączy. , cała transakcja zaczyna się od początku. –

+0

OTOH, jeśli nie korzystasz z transakcji, użycie funkcji automatycznego ponownego nawiązywania połączenia jest prawdopodobnie mniejszym problemem. –

5

Z Rails 2.3 release notes (kopalnia nacisk):

4.8 podłączając MySQL Połączenia

MySQL obsługuje flagę ponownego połączenia w jego połączeń - jeśli ma wartość true, wówczas klient spróbuje ponownie połączyć się z serwerem, zanim zrezygnuje z utraconego połączenia. Teraz możesz ustawić reconnect = true dla połączeń MySQL w database.yml, aby uzyskać to zachowanie z aplikacji Rails. Wartość domyślna to false, , więc zachowanie istniejących aplikacji nie zmienia się.

Powiązane problemy