2014-12-02 12 views
5

Niedawno znalazłem wiele błędów zakleszczeń w mojej aplikacji.Mysql2 :: Błąd: zakleszczenie znalezione podczas próby uzyskania blokady; spróbuj ponownie uruchomić transakcję: INSERT INTO

Mysql2::Error: Deadlock found when trying to get lock; try restarting transaction: INSERT INTO `products`.... 

kod jak poniżej:

Po użytkownik został utworzony, dodam kilka produktów do użytkownika. Nie rozumiem, dlaczego doszło do impasu.

class User < ActiveRecord::Base 
    after_create :add_products 
    has_many :products, :dependent => :destroy 

    def self.create_user 
     User.create!(.......) 
    end 

    def add_products 
     Product.add(self, "product_name", 10) 
    end 
    ..... 
end 

class Product < ActiveRecord::Base 
    belongs_to :user 

    def self.add(user, product_name, amount) 
     transaction do 
     product = user.products.find_by_product_name(product_name) 
     if product 
      product.increment :amount, amount 
      product.save! 
     else 
      product = self.create! user_id: user.id, 
            product_name: product_name, 
            amount: amount 
     end 
     end 
     product 
    end 
end 

Nie znalazłem przyczyny, czy ktoś może mi doradzić? Z góry dziękuję!!!

+0

zw sposób dodawać, Czemu znowu używając siebie.? Zamiast tego użyj produktu. – Jyothu

+0

Masz rację, już zmodyfikowałem. – pangpang

+0

Patrz poniższy link, to pomoże Ci http://stackoverflow.com/questions/2332768/how-to-avoid-mysql-deadlock-found-when-trying-to-get-lock-try- restarting-trans – Sush

Odpowiedz

9

Domyślam się, że używasz InnoDB i prawdopodobnie robisz jednoczesne wstawienia.

Aby prześledzić i zrozumieć kasie powodować te artykuły

jeden sposób, aby rozwiązać ten problem jest, aby ponowić próbę jak poniżej kod

def add_products 
    retries = 0 

    begin 
     Product.add(self, "product_name", 10) 
    rescue ActiveRecord::StatementInvalid => ex 
     if ex.message =~ /Deadlock found when trying to get lock/ #ex not e!! 
      retries += 1 
      raise ex if retries > 3 ## max 3 retries 
      sleep 10 
      retry 
     else 
      raise ex 
     end 
    end 
end 

Lub istnieje kilka klejnotów takich jak transaction_query do obsługi zakleszczeń MySQL.

+0

Mam pytanie: zapisywanie i tworzenie metod jest zawijane wewnątrz transakcji, czy nie jest konieczne dodawanie transakcji do metody "dodaj"? – pangpang

+0

Transakcja jest niezbędna, jeśli masz wiele wstawień, aby upewnić się, że wszystkie są skuteczne lub przerwać. Zależy całkowicie od implementacji, ale patrząc na dostarczony kod, powiedziałbym, że nie jest to konieczne. – shiva

2

To zaoszczędziło mi wielu bólów głowy: transaction_retry klejnot ruby.

Od README klejnotu:

Retries database transaction on deadlock and transaction serialization errors. Supports MySQL, PostgreSQL, and SQLite.

+1

Przepraszam, wiem, że masz dobrą reputację na tej stronie, ale ... ta odpowiedź jest tylko linkem, a nie spamem. Gdybyś mógł rzucić trochę więcej światła na to, jak to mogłoby pomóc w pytaniu, byłby to docenione. – iGbanam

+0

@Yasky to klejnot, który zajmuje się dokładnie takimi problemami, o które pyta. W środowisku współbieżnym czasami zakleszczenia są nieuniknione, jedynym sposobem jest po prostu ponowienie transakcji. Ten klejnot automatycznie wykonuje to zadanie. – fguillen

Powiązane problemy