Spec-Zone.ru › Ruby on Rails 6.1

класс 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::Base.connection_handler. Все модели Active Record используют этот обработчик для определения пула соединений, который они должны использовать.

Класс ConnectionHandler не связан с моделями Active Record, так как он не имеет информации о модели. Модель должна передать имя спецификации подключения обработчику, чтобы найти правильный пул соединений.

Публичные методы класса

new() Показать исходный код
# File activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb, line 992
def initialize
  # These caches are keyed by pool_config.connection_specification_name (PoolConfig#connection_specification_name).
  @owner_to_pool_manager = Concurrent::Map.new(initial_capacity: 2)

  # Backup finalizer: if the forked child skipped Kernel#fork the early discard has not occurred
  ObjectSpace.define_finalizer self, FINALIZER
end

Публичные методы экземпляра

active_connections?(role = ActiveRecord::Base.current_role) Показать исходный код
# File activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb, line 1078
def active_connections?(role = ActiveRecord::Base.current_role)
  connection_pool_list(role).any?(&:active_connection?)
end

Возвращает true, если среди пулов соединений, управляемых ConnectionHandler, есть активные подключения.

all_connection_pools() Показать исходный код
# File activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb, line 1034
def all_connection_pools
  owner_to_pool_manager.values.flat_map { |m| m.pool_configs.map(&:pool) }
end
clear_active_connections!(role = ActiveRecord::Base.current_role) Показать исходный код
# File activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb, line 1085
def clear_active_connections!(role = ActiveRecord::Base.current_role)
  connection_pool_list(role).each(&:release_connection)
end

Возвращает все используемые текущей нитью подключения обратно в пул, а также подключения, кэшированные нитями, которые больше неактивны.

clear_all_connections!(role = ActiveRecord::Base.current_role) Показать исходный код
# File activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb, line 1096
def clear_all_connections!(role = ActiveRecord::Base.current_role)
  connection_pool_list(role).each(&:disconnect!)
end
clear_reloadable_connections!(role = ActiveRecord::Base.current_role) Показать исходный код
# File activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb, line 1092
def clear_reloadable_connections!(role = ActiveRecord::Base.current_role)
  connection_pool_list(role).each(&:clear_reloadable_connections!)
end

Очищает кэш, который сопоставляет классы.

См. ConnectionPool#clear_reloadable_connections! для подробностей.

connected?(spec_name, role: ActiveRecord::Base.current_role, shard: ActiveRecord::Base.current_shard) Показать исходный код
# File activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb, line 1133
def connected?(spec_name, role: ActiveRecord::Base.current_role, shard: ActiveRecord::Base.current_shard)
  pool = retrieve_connection_pool(spec_name, role: role, shard: shard)
  pool && pool.connected?
end

Возвращает true, если подключение, доступное для этого класса, уже открыто.

connection_pool_list(role = ActiveRecord::Base.current_role) Показать исходный код
# File activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb, line 1038
def connection_pool_list(role = ActiveRecord::Base.current_role)
  owner_to_pool_manager.values.flat_map { |m| m.pool_configs(role).map(&:pool) }
end
Также алиас: connection_pools
connection_pools(role = ActiveRecord::Base.current_role)
Алиас для: connection_pool_list
establish_connection(config, owner_name: Base.name, role: ActiveRecord::Base.current_role, shard: Base.current_shard) Показать исходный код
# File activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb, line 1043
def establish_connection(config, owner_name: Base.name, role: ActiveRecord::Base.current_role, shard: Base.current_shard)
  owner_name = config.to_s if config.is_a?(Symbol)

  pool_config = resolve_pool_config(config, owner_name)
  db_config = pool_config.db_config

  # Protects the connection named `ActiveRecord::Base` from being removed
  # if the user calls `establish_connection :primary`.
  if owner_to_pool_manager.key?(pool_config.connection_specification_name)
    remove_connection_pool(pool_config.connection_specification_name, role: role, shard: shard)
  end

  message_bus = ActiveSupport::Notifications.instrumenter
  payload = {}
  if pool_config
    payload[:spec_name] = pool_config.connection_specification_name
    payload[:shard] = shard
    payload[:config] = db_config.configuration_hash
  end

  if ActiveRecord::Base.legacy_connection_handling
    owner_to_pool_manager[pool_config.connection_specification_name] ||= LegacyPoolManager.new
  else
    owner_to_pool_manager[pool_config.connection_specification_name] ||= PoolManager.new
  end
  pool_manager = get_pool_manager(pool_config.connection_specification_name)
  pool_manager.set_pool_config(role, shard, pool_config)

  message_bus.instrument("!connection.active_record", payload) do
    pool_config.pool
  end
end
flush_idle_connections!(role = ActiveRecord::Base.current_role) Показать исходный код
# File activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb, line 1103
def flush_idle_connections!(role = ActiveRecord::Base.current_role)
  connection_pool_list(role).each(&:flush!)
end

Отключает все в настоящее время бездействующие подключения.

См. ConnectionPool#flush! для подробностей.

remove_connection(owner, role: ActiveRecord::Base.current_role, shard: ActiveRecord::Base.current_shard) Показать исходный код
# File activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb, line 1142
def remove_connection(owner, role: ActiveRecord::Base.current_role, shard: ActiveRecord::Base.current_shard)
  remove_connection_pool(owner, role: role, shard: shard)&.configuration_hash
end

Удаляет подключение для данного класса. Это закроет активное подключение и определенное подключение (если они существуют). Результат может быть использован в качестве аргумента для establish_connection для лёгкого повторного установления подключения.

remove_connection_pool(owner, role: ActiveRecord::Base.current_role, shard: ActiveRecord::Base.current_shard) Показать исходный код
# File activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb, line 1147
def remove_connection_pool(owner, role: ActiveRecord::Base.current_role, shard: ActiveRecord::Base.current_shard)
  if pool_manager = get_pool_manager(owner)
    pool_config = pool_manager.remove_pool_config(role, shard)

    if pool_config
      pool_config.disconnect!
      pool_config.db_config
    end
  end
end
retrieve_connection_pool(owner, role: ActiveRecord::Base.current_role, shard: ActiveRecord::Base.current_shard) Показать исходный код
# File activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb, line 1161
def retrieve_connection_pool(owner, role: ActiveRecord::Base.current_role, shard: ActiveRecord::Base.current_shard)
  pool_config = get_pool_manager(owner)&.get_pool_config(role, shard)
  pool_config&.pool
end

Получение пула соединений происходит часто, поэтому мы кэшируем его в @owner_to_pool_manager. Это делает получение пула соединений O(1) после того, как процесс прогреется. При установлении или удалении подключения мы аннулируем кэш.

while_preventing_writes(enabled = true) { || ... } Показать исходный код
# File activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb, line 1019
def while_preventing_writes(enabled = true)
  unless ActiveRecord::Base.legacy_connection_handling
    raise NotImplementedError, "`while_preventing_writes` is only available on the connection_handler with legacy_connection_handling"
  end

  original, self.prevent_writes = self.prevent_writes, enabled
  yield
ensure
  self.prevent_writes = original
end

Запрещает запись в базу данных независимо от роли.

В некоторых случаях вам может потребоваться запретить запись в базу данных, даже если вы работаете с базой данных, которая может записывать. `while_preventing_writes` запретит запись в базу данных на время выполнения блока.

Этот метод не предоставляет той же защиты, что и пользователь с правами чтения, и предназначен для защиты от случайных записей.

См. `READ_QUERY` для запросов, которые блокируются этим методом.

© 2004–2020 David Heinemeier Hansson
Licensed under the MIT License.

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API