Active Record 連線處理器
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」。
這些不同的連線池由透過 ActiveRecord::Base.connection_handler
可存取的單一 ConnectionHandler
執行個體來管理。所有 Active Record 模型使用此處理器來決定應使用的連線池。
ConnectionHandler
類別不會與 Active 模型結合,因為它不了解模型。模塊必須將連線規格名稱傳遞給處理器,才能查閱正確的連線池。
- A
- C
- E
- F
- N
- R
類別公用方法
new() 連結
來源: 顯示 | 在 GitHub 上
# File activerecord/lib/active_record/connection_adapters/abstract/connection_handler.rb, line 73 def initialize # These caches are keyed by pool_config.connection_name (PoolConfig#connection_name). @connection_name_to_pool_manager = Concurrent::Map.new(initial_capacity: 2) end
執行個體公用方法
active_connections?(role = nil) 連結
如果 ConnectionHandler
正在管理的連線池之間有任何活動連線,則傳回 true。
來源: 顯示 | 在 GitHub 上
# File activerecord/lib/active_record/connection_adapters/abstract/connection_handler.rb, line 154 def active_connections?(role = nil) each_connection_pool(role).any?(&:active_connection?) end
clear_active_connections!(role = nil) 連結
將目前執行緒使用中任何連線傳回池中,且傳回未執行緒使用、暫存在緩存中的連線至池中。
來源: 顯示 | 在 GitHub 上
# File activerecord/lib/active_record/connection_adapters/abstract/connection_handler.rb, line 161 def clear_active_connections!(role = nil) each_connection_pool(role).each do |pool| pool.release_connection pool.disable_query_cache! end end
clear_all_connections!(role = nil) 連結
來源: 顯示 | 在 GitHub 上
# File activerecord/lib/active_record/connection_adapters/abstract/connection_handler.rb, line 175 def clear_all_connections!(role = nil) each_connection_pool(role).each(&:disconnect!) end
clear_reloadable_connections!(role = nil) 連結
清除對應類別的快取。
原始碼: 顯示 | 於 GitHub 上
# File activerecord/lib/active_record/connection_adapters/abstract/connection_handler.rb, line 171 def clear_reloadable_connections!(role = nil) each_connection_pool(role).each(&:clear_reloadable_connections!) end
connected?(connection_name, role: ActiveRecord::Base.current_role, shard: ActiveRecord::Base.current_shard) 連結
如果已開啟可供此類別存取的連線,則傳回 true。
原始碼: 顯示 | 於 GitHub 上
# File activerecord/lib/active_record/connection_adapters/abstract/connection_handler.rb, line 197 def connected?(connection_name, role: ActiveRecord::Base.current_role, shard: ActiveRecord::Base.current_shard) pool = retrieve_connection_pool(connection_name, role: role, shard: shard) pool && pool.connected? end
connection_pool_list(role = nil) 連結
傳回連線處理常式和特定角色的池。如果傳入 :all
,則會傳回連線處理常式下的所有池。
原始碼: 顯示 | 於 GitHub 上
# File activerecord/lib/active_record/connection_adapters/abstract/connection_handler.rb, line 92 def connection_pool_list(role = nil) if role.nil? || role == :all connection_name_to_pool_manager.values.flat_map { |m| m.pool_configs.map(&:pool) } else connection_name_to_pool_manager.values.flat_map { |m| m.pool_configs(role).map(&:pool) } end end
establish_connection(config, owner_name: Base, role: Base.current_role, shard: Base.current_shard, clobber: false) 連結
原始碼: 顯示 | 於 GitHub 上
# File activerecord/lib/active_record/connection_adapters/abstract/connection_handler.rb, line 112 def establish_connection(config, owner_name: Base, role: Base.current_role, shard: Base.current_shard, clobber: false) owner_name = determine_owner_name(owner_name, config) pool_config = resolve_pool_config(config, owner_name, role, shard) db_config = pool_config.db_config pool_manager = set_pool_manager(pool_config.connection_name) # If there is an existing pool with the same values as the pool_config # don't remove the connection. Connections should only be removed if we are # establishing a connection on a class that is already connected to a different # configuration. existing_pool_config = pool_manager.get_pool_config(role, shard) if !clobber && existing_pool_config && existing_pool_config.db_config == db_config # Update the pool_config's connection class if it differs. This is used # for ensuring that ActiveRecord::Base and the primary_abstract_class use # the same pool. Without this granular swapping will not work correctly. if owner_name.primary_class? && (existing_pool_config.connection_class != owner_name) existing_pool_config.connection_class = owner_name end existing_pool_config.pool else disconnect_pool_from_pool_manager(pool_manager, role, shard) pool_manager.set_pool_config(role, shard, pool_config) payload = { connection_name: pool_config.connection_name, role: role, shard: shard, config: db_config.configuration_hash } ActiveSupport::Notifications.instrumenter.instrument("!connection.active_record", payload) do pool_config.pool end end end
flush_idle_connections!(role = nil) 連結
中斷所有目前的閒置連線。
更多資訊,請參閱 ConnectionPool#flush!
。
原始碼: 顯示 | 於 GitHub 上
# File activerecord/lib/active_record/connection_adapters/abstract/connection_handler.rb, line 182 def flush_idle_connections!(role = nil) each_connection_pool(role).each(&:flush!) end
remove_connection_pool(connection_name, role: ActiveRecord::Base.current_role, shard: ActiveRecord::Base.current_shard) 連結
原始碼: 顯示 | 於 GitHub 上
# File activerecord/lib/active_record/connection_adapters/abstract/connection_handler.rb, line 202 def remove_connection_pool(connection_name, role: ActiveRecord::Base.current_role, shard: ActiveRecord::Base.current_shard) if pool_manager = get_pool_manager(connection_name) disconnect_pool_from_pool_manager(pool_manager, role, shard) end end
retrieve_connection_pool(connection_name, role: ActiveRecord::Base.current_role, shard: ActiveRecord::Base.current_shard, strict: false) 連結
擷取連線池的動作頻率很高,因此我們將它快取在 @connection_name_to_pool_manager 中。這樣一來,只要處理程序是熱的,擷取連線池的動作便能達到 O(1) 的效能。系統會在建立或移除連線時,取消快取。
原始碼: 顯示 | 於 GitHub 上
# File activerecord/lib/active_record/connection_adapters/abstract/connection_handler.rb, line 211 def retrieve_connection_pool(connection_name, role: ActiveRecord::Base.current_role, shard: ActiveRecord::Base.current_shard, strict: false) pool_manager = get_pool_manager(connection_name) pool = pool_manager&.get_pool_config(role, shard)&.pool if strict && !pool selector = [ ("'#{shard}' shard" unless shard == ActiveRecord::Base.default_shard), ("'#{role}' role" unless role == ActiveRecord::Base.default_role), ].compact.join(" and ") selector = [ (connection_name unless connection_name == "ActiveRecord::Base"), selector.presence, ].compact.join(" with ") selector = " for #{selector}" if selector.present? message = "No database connection defined#{selector}." raise ConnectionNotDefined.new(message, connection_name: connection_name, shard: shard, role: role) end pool end