Rails Как коснуться объекта активной записи без блокировки?

В моем классе фотографий у меня есть эта ассоциация.

belongs_to :user, :touch => true

Однажды я получил это исключение.

A ActiveRecord::StatementInvalid occurred in photos#update:

 Mysql::Error: Deadlock found when trying to get lock; try restarting transaction:
 UPDATE `users` SET `updated_at` = '2011-09-20 14:17:44' WHERE `users`.`id` = 6832
 production/ruby/1.8/gems/activerecord-3.0.10/lib/active_record/connection_adapters/abstract_adapter.rb:207:in `log'

Что делать, чтобы предотвратить появление таких исключений в будущем? Я хотел бы, чтобы оператор обновления, показанный в ошибке, не использовал блокировку, если это было возможно. Я не думаю, что использование оптимистической блокировки будет работать в этом случае, потому что оптимистическая блокировка, вероятно, приведет к активации ActiveRecord:: StaleObjectError.

Ответ 1

Я тоже наткнулся на себя.

Короткий ответ. С этой проблемой нелегко. Все touch es завернуты в ту же транзакцию, следовательно, тупик.

Длинный ответ. Я предполагаю, что вам нужны сенсорные объекты, чтобы аннулировать некоторые (зависимые) кеши. Обычно рекомендуемое использование touch работает только для ограниченного количества "отношений". Например. аннулирование статьи при обновлении комментария.

Моим решением была асинхронная коллекция (с использованием задания sidekiq) объектов БД, которые должны быть недействительными. Я написал для себя свою собственную логику управления, которая определяет, какие (другие) объекты должны быть аннулированы при изменении объекта. Например. комментарий == > статья.

Таким образом, у нас был более сложный способ аннулирования зависимых объектов. Плюс я признал недействительным, используя Model.update_all, который был быстрее, чем "сенсорная цепочка". Он решил наши проблемы с тупиком (и добавил многословие и производительность к недействительности кеша).

Дополнительный совет: не используйте updated_at. Это очень спорно, если объект DB действительно изменился, потому что другой объект изменился. Перезапись модели cache_key позволяет легко определить пользовательский кеш-ключ, например "#{id}-#{valid_from}". valid_from может быть временной меткой, которую вы определяете на своих моделях (и которую вы используете вместо updated_at).