класс ActiveRecord::ConnectionAdapters::ConnectionHandler
ConnectionHandler — это коллекция объектов ConnectionPool. Она используется для хранения отдельных пулов соединений, подключающихся к различным базам данных.
Например, предположим, что у вас есть 5 моделей с такой иерархией:
class Author < ActiveRecord::Base end class BankAccount < ActiveRecord::Base end class Book < ActiveRecord::Base establish_connection :library_db end class ScaryBook < Book end class GoodBook < Book end
И файл database.yml, который выглядит так:
development: database: my_application host: localhost library_db: database: library host: some.library.org
Вашей основной базой данных в среде разработки является «my_application», но модель Book подключается к отдельной базе данных под названием «library_db» (это может быть даже база данных на другом компьютере).
Book, ScaryBook и GoodBook будут использовать один и тот же пул соединений для «library_db», в то время как Author, BankAccount и любые другие созданные вами модели будут использовать стандартный пул соединений для «my_application».
Различные пулы соединений управляются одним экземпляром ConnectionHandler, доступным через ActiveRecord::Core.connection_handler. Все модели Active Record используют этот обработчик для определения пула соединений, который они должны использовать.
Класс ConnectionHandler не связан с моделями Active, так как он не имеет информации о модели. Модель должна передать имя спецификации обработчику, чтобы найти правильный пул соединений.
Публичные методы класса
# File activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb, line 1008 def initialize # These caches are keyed by spec.name (ConnectionSpecification#name). @owner_to_pool = ConnectionHandler.create_owner_to_pool # Backup finalizer: if the forked child never needed a pool, the above # early discard has not occurred ObjectSpace.define_finalizer self, ConnectionHandler.unowned_pool_finalizer(@owner_to_pool) end
Публичные методы экземпляра
# File activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb, line 1066 def active_connections? connection_pool_list.any?(&:active_connection?) end
Возвращает true, если среди пулов соединений, которые управляет ConnectionHandler, существуют активные соединения.
# File activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb, line 1073 def clear_active_connections! connection_pool_list.each(&:release_connection) end
Возвращает любые используемые текущей нитью соединения обратно в пул, а также возвращает соединения в пул, кэшированные нитями, которые больше не существуют.
# File activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb, line 1084 def clear_all_connections! connection_pool_list.each(&:disconnect!) end
# File activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb, line 1080 def clear_reloadable_connections! connection_pool_list.each(&:clear_reloadable_connections!) end
Очищает кэш, который сопоставляет классы.
Подробности см. в ActiveRecord::ConnectionAdapters::ConnectionPool#clear_reloadable_connections!.
# File activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb, line 1116 def connected?(spec_name) pool = retrieve_connection_pool(spec_name) pool && pool.connected? end
Возвращает true, если соединение, доступное для данного класса, уже открыто.
# File activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb, line 1037 def connection_pool_list owner_to_pool.values.compact end
# File activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb, line 1042
def establish_connection(config)
resolver = ConnectionSpecification::Resolver.new(Base.configurations)
spec = resolver.spec(config)
remove_connection(spec.name)
message_bus = ActiveSupport::Notifications.instrumenter
payload = {
connection_id: object_id
}
if spec
payload[:spec_name] = spec.name
payload[:config] = spec.config
end
message_bus.instrument("!connection.active_record", payload) do
owner_to_pool[spec.name] = ConnectionAdapters::ConnectionPool.new(spec)
end
owner_to_pool[spec.name]
end # File activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb, line 1091 def flush_idle_connections! connection_pool_list.each(&:flush!) end
Отключает все в настоящее время неиспользуемые соединения.
Подробности см. в ActiveRecord::ConnectionAdapters::ConnectionPool#flush!.
# File activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb, line 1125
def remove_connection(spec_name)
if pool = owner_to_pool.delete(spec_name)
pool.automatic_reconnect = false
pool.disconnect!
pool.spec.config
end
end Удаляет соединение для данного класса. Это закроет активное соединение и определенное соединение (если они существуют). Результат может быть использован в качестве аргумента для establish_connection для лёгкого повторного подключения.
# File activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb, line 1136
def retrieve_connection_pool(spec_name)
owner_to_pool.fetch(spec_name) do
# Check if a connection was previously established in an ancestor process,
# which may have been forked.
if ancestor_pool = pool_from_any_process_for(spec_name)
# A connection was established in an ancestor process that must have
# subsequently forked. We can't reuse the connection, but we can copy
# the specification and establish a new connection with it.
establish_connection(ancestor_pool.spec.to_hash).tap do |pool|
pool.schema_cache = ancestor_pool.schema_cache if ancestor_pool.schema_cache
end
else
owner_to_pool[spec_name] = nil
end
end
end Извлечение пула соединений происходит часто, поэтому мы кешируем его в @owner_to_pool. Это делает извлечение пула соединений O(1) после предварительной загрузки процесса. При установлении или удалении соединения мы аннулируем кеш.
# File activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb, line 1030 def while_preventing_writes(enabled = true) original, self.prevent_writes = self.prevent_writes, enabled yield ensure self.prevent_writes = original end
Запрещает запись в базу данных независимо от роли.
В некоторых случаях вам может потребоваться запретить запись в базу данных, даже если вы работаете с базой данных, которая может записывать. `while_preventing_writes` запретит запись в базу данных на период выполнения блока.
© 2004–2019 David Heinemeier Hansson
Licensed under the MIT License.