class ActiveRecord::ConnectionAdapters::AbstractAdapter
Абстрактный адаптер Active Record
Active Record поддерживает несколько систем управления базами данных. AbstractAdapter и связанные классы образуют уровень абстракции, благодаря которому это возможно. AbstractAdapter представляет собой подключение к базе данных и предоставляет абстрактный интерфейс для функций, специфичных для базы данных, таких как установление подключения, экранирование значений, формирование подходящих фрагментов SQL для параметров :offset и :limit и т. д.
Все конкретные адаптеры баз данных реализуют интерфейс, определенный в этом классе. ActiveRecord::Base.lease_connection возвращает объект AbstractAdapter, который можно использовать.
Большинство методов адаптера полезны при выполнении миграций. Особенно полезны методы экземпляра, предоставляемые SchemaStatements.
Константы
- ADAPTER_NAME
- COMMENT_REGEX
- EXTENDED_TYPE_MAPS
- SIMPLE_INT
- TYPE_MAP
Атрибуты
Публичные методы класса
# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 403 def self.database_exists?(config) new(config).database_exists? end
Существует ли база данных для этого адаптера?
# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 128
def self.dbconsole(config, options = {})
raise NotImplementedError.new("#{self.class} should define `dbconsole` that accepts a db config and options to implement connecting to the db console")
end Открывает сеанс консоли базы данных.
# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 99
def self.find_cmd_and_exec(commands, *args) # :doc:
commands = Array(commands)
dirs_on_path = ENV["PATH"].to_s.split(File::PATH_SEPARATOR)
unless (ext = RbConfig::CONFIG["EXEEXT"]).empty?
commands = commands.map { |cmd| "#{cmd}#{ext}" }
end
full_path_command = nil
found = commands.detect do |cmd|
dirs_on_path.detect do |path|
full_path_command = File.join(path, cmd)
begin
stat = File.stat(full_path_command)
rescue SystemCallError
else
stat.file? && stat.executable?
end
end
end
if found
exec full_path_command, *args
else
abort("Couldn't find database client: #{commands.join(', ')}. Check your $PATH and try again.")
end
end # File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 72
def self.type_cast_config_to_boolean(config)
if config == "false"
false
else
config
end
end # File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 62
def self.type_cast_config_to_integer(config)
if config.is_a?(Integer)
config
elsif SIMPLE_INT.match?(config)
config.to_i
else
config
end
end # File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 80
def self.validate_default_timezone(config)
case config
when nil
when "utc", "local"
config.to_sym
else
raise ArgumentError, "default_timezone must be either 'utc' or 'local'"
end
end Публичные методы экземпляра
# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 705 def active? end
Проверяет, активно ли соединение с базой данных. В том числе проверяет, способна ли база данных отвечать на запросы, то есть не устарело ли соединение.
# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 398 def adapter_name self.class::ADAPTER_NAME end
Возвращает удобочитаемое название адаптера. Используется смешанный регистр — при необходимости всегда можно преобразовать название к нижнему регистру.
# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 690 def check_all_foreign_keys_valid! end
Переопределите этот метод, чтобы проверить все ограничения внешних ключей в базе данных. Если ограничения внешних ключей не соблюдаются, адаптер должен вызывать исключение ActiveRecord::StatementInvalid.
# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 795
def clear_cache!(new_connection: false)
if @statements
@lock.synchronize do
if new_connection
@statements.reset
else
@statements.clear
end
end
end
end Очищает все кэши, которые может использовать адаптер базы данных.
# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 897 def close pool.checkin self end
Возвращает соединение в пул соединений.
# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 838 def connect! verify! self end
# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 698 def connected? !@raw_connection.nil? end
Проверяет, установлено ли соединение с базой данных. При этом не проверяется, способна ли база данных отвечать на запросы, то есть не устарело ли соединение.
# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 221 def connection_retries (@config[:connection_retries] || 1).to_i end
# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 407 def database_exists? connect! true rescue ActiveRecord::NoDatabaseError false end
# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 237 def default_timezone @default_timezone || ActiveRecord.default_timezone end
# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 617 def disable_extension(name, **) end
Этот метод должны реализовывать адаптеры, поддерживающие расширения.
# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 683 def disable_referential_integrity yield end
Переопределите этот метод, чтобы отключить ссылочную целостность при выполнении &block.
# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 768 def discard! # This should be overridden by concrete adapters. end
Немедленно забывает об этом соединении. В отличие от disconnect!, этот метод не взаимодействует с сервером.
После вызова этого метода поведение всех остальных методов становится неопределённым. Этот метод вызывается внутри программы непосредственно перед тем, как разветвлённый процесс избавляется от соединения, принадлежавшего родительскому процессу.
# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 751
def disconnect!
@lock.synchronize do
clear_cache!(new_connection: true)
reset_transaction
@raw_connection_dirty = false
@connected_since = nil
@last_activity = nil
@verified = false
end
end Отключается от базы данных, если соединение уже установлено. В противном случае ничего не делает.
# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 621 def enable_extension(name, **) end
Этот метод должны реализовывать адаптеры, поддерживающие расширения.
# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 671 def extensions [] end
Список расширений, который заполняют адаптеры, поддерживающие их.
# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 676
def index_algorithms
{}
end Список алгоритмов индексации, который заполняют адаптеры, поддерживающие их.
# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 289
def lease
if in_use?
msg = +"Cannot lease connection, "
if @owner == ActiveSupport::IsolatedExecutionState.context
msg << "it is already leased by the current thread."
else
msg << "it is already in use by a different thread: #{@owner}. " \
"Current thread: #{ActiveSupport::IsolatedExecutionState.context}."
end
raise ActiveRecordError, msg
end
@owner = ActiveSupport::IsolatedExecutionState.context
end Этот метод можно вызывать только при захваченном мьютексе пула соединений.
# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 213 def max_jitter (@config[:pool_jitter] || 0.2).to_f.clamp(MAX_JITTER) end
# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 50 def pool=(value) return if value.eql?(@pool) @schema_cache = nil @pool = value end
# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 324 def pool_jitter(duration) duration * (1.0 - @pool_jitter) end
# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 447 def prefetch_primary_key?(table_name = nil) false end
Следует ли получать значения первичного ключа из соответствующей последовательности до выполнения оператора вставки? Если возвращается true, перед каждой вставкой вызывается next_sequence_value, чтобы задать первичный ключ записи.
# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 252 def prepared_statements? @prepared_statements && !prepared_statements_disabled_cache.include?(object_id) end
# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 245 def preventing_writes? return true if replica? return false if connection_descriptor.nil? connection_descriptor.current_preventing_writes end
Определяет, запрещена ли сейчас запись.
Возвращает true, если соединение является репликой, или значение current_preventing_writes.
# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 865
def raw_connection
with_raw_connection do |conn|
disable_lazy_transactions!
@raw_connection_dirty = true
conn
end
end Предоставляет доступ к базовому драйверу базы данных для этого адаптера. Например, для Mysql2Adapter этот метод возвращает объект Mysql2::Client, а для PostgreSQLAdapter — объект PG::Connection.
Это полезно, когда нужно вызвать проприетарный метод, например методы PostgreSQL lo_*.
Active Record не может отслеживать изменения в базе данных, выполняемые с помощью этого клиента. В таком случае обычно следует сбросить кэш запросов с помощью ActiveRecord::Base.clear_query_cache.
# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 711
def reconnect!(restore_transactions: false)
retries_available = connection_retries
deadline = retry_deadline && Process.clock_gettime(Process::CLOCK_MONOTONIC) + retry_deadline
@lock.synchronize do
attempt_configure_connection do
@allow_preconnect = false
reconnect
enable_lazy_transactions!
@raw_connection_dirty = false
@last_activity = @connected_since = Process.clock_gettime(Process::CLOCK_MONOTONIC)
@verified = true
@allow_preconnect = true
reset_transaction(restore: restore_transactions) do
clear_cache!(new_connection: true)
configure_connection
end
rescue => original_exception
translated_exception = translate_exception_class(original_exception, nil, nil)
retry_deadline_exceeded = deadline && deadline < Process.clock_gettime(Process::CLOCK_MONOTONIC)
if !retry_deadline_exceeded && retries_available > 0
retries_available -= 1
if retryable_connection_error?(translated_exception)
backoff(connection_retries - retries_available)
retry
end
end
raise translated_exception
end
end
end Отключается от базы данных, если соединение уже установлено, и устанавливает новое соединение с базой данных. Реализующие этот метод классы должны определить приватный метод reconnect.
# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 217 def replica? @config[:replica] || false end
# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 808 def requires_reloading? false end
Возвращает true, если в режиме разработки соединение необходимо перезагружать между запросами.
# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 780
def reset!
attempt_configure_connection do
clear_cache!(new_connection: true)
reset_transaction
configure_connection
end
end Сбрасывает состояние этого соединения, указывая СУБД очистить транзакции и другое состояние на стороне сервера, связанное с соединением. Обычно эта операция зависит от используемой базы данных.
Если драйвер базы данных или протокол не поддерживает такую возможность, реализующие этот метод классы могут назначить ему псевдоним reconnect!. В противном случае после сброса соединения реализующие этот метод классы должны немедленно вызвать super, продолжая удерживать @lock.
# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 229
def retry_deadline
if @config[:retry_deadline]
@config[:retry_deadline].to_f
else
nil
end
end # File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 310 def role @pool.role end
Роль (например, :writing) текущего соединения. В приложении без нескольких ролей возвращается :writing.
# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 431 def savepoint_errors_invalidate_transactions? false end
Влияют ли ошибки TransactionRollbackError в точках сохранения на родительскую транзакцию?
# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 320 def schema_cache @pool.schema_cache || (@schema_cache ||= BoundSchemaReflection.for_lone_connection(@pool.schema_reflection, self)) end
# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 932 def schema_version pool.migration_context.current_version end
Возвращает идентификатор версии схемы, доступной в базе данных. Обычно он равен номеру самой старшей выполненной миграции или 0, если сведения о схеме отсутствуют / база данных пуста.
# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 316 def shard @pool.shard end
Шард (например, :default) текущего соединения. В приложении без шардирования возвращается :default.
# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 440 def supports_advisory_locks? false end
Поддерживает ли этот адаптер блокировки, управляемые приложением?
# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 420 def supports_bulk_alter? false end
# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 512 def supports_check_constraints? false end
Поддерживает ли этот адаптер создание ограничений CHECK?
# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 547 def supports_comments? false end
Поддерживает ли этот адаптер комментарии с метаданными для объектов базы данных (таблиц, столбцов, индексов)?
# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 552 def supports_comments_in_create? false end
Можно ли задавать комментарии для таблиц, столбцов и индексов в операторах создания или изменения таблиц?
# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 571 def supports_common_table_expressions? false end
# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 595 def supports_concurrent_connections? true end
# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 537 def supports_datetime_with_precision? false end
Поддерживает ли этот адаптер дату и время с заданной точностью?
# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 416 def supports_ddl_transactions? false end
Поддерживает ли этот адаптер откат DDL-операций в транзакциях? Иными словами, будут ли операторы CREATE TABLE или ALTER TABLE отменены при откате транзакции?
# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 507 def supports_deferrable_constraints? false end
Поддерживает ли этот адаптер создание отложенных ограничений?
# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 603 def supports_disabling_indexes? false end
# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 517 def supports_exclusion_constraints? false end
Поддерживает ли этот адаптер создание ограничений-исключений?
# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 476 def supports_explain? false end
Поддерживает ли этот адаптер оператор EXPLAIN?
# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 471 def supports_expression_index? false end
Поддерживает ли этот адаптер индексы по выражениям?
# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 486 def supports_extensions? false end
Поддерживает ли этот адаптер расширения базы данных?
# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 497 def supports_foreign_keys? false end
Поддерживает ли этот адаптер создание ограничений внешних ключей?
# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 562 def supports_foreign_tables? false end
Поддерживает ли этот адаптер внешние таблицы?
# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 466 def supports_index_include? false end
Поддерживает ли этот адаптер включение столбцов, не являющихся ключами?
# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 456 def supports_index_sort_order? false end
Поддерживает ли этот адаптер порядок сортировки индекса?
# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 492 def supports_indexes_in_create? false end
Поддерживает ли этот адаптер создание индексов в той же инструкции, что и создание таблицы?
# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 591 def supports_insert_conflict_target? false end
# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 583 def supports_insert_on_duplicate_skip? false end
# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 587 def supports_insert_on_duplicate_update? false end
# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 579 def supports_insert_returning? false end
# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 542 def supports_json? false end
Поддерживает ли этот адаптер тип данных JSON?
# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 575 def supports_lazy_transactions? false end
# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 532 def supports_materialized_views? false end
Поддерживает ли этот адаптер материализованные представления?
# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 599 def supports_nulls_not_distinct? false end
# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 567 def supports_optimizer_hints? false end
Поддерживает ли этот адаптер подсказки оптимизатору?
# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 461 def supports_partial_index? false end
Поддерживает ли этот адаптер частичные индексы?
# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 451 def supports_partitioned_indexes? false end
# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 435 def supports_restart_db_transaction? false end
# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 425 def supports_savepoints? false end
Поддерживает ли этот адаптер точки сохранения?
# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 481 def supports_transaction_isolation? false end
Поддерживает ли этот адаптер настройку уровня изоляции транзакции?
# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 522 def supports_unique_constraints? false end
Поддерживает ли этот адаптер создание ограничений уникальности?
# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 502 def supports_validate_constraints? false end
Поддерживает ли этот адаптер создание непроверенных ограничений?
# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 527 def supports_views? false end
Поддерживает ли этот адаптер представления?
# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 557 def supports_virtual_columns? false end
Поддерживает ли этот адаптер виртуальные столбцы?
# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 789 def throw_away! pool.remove self disconnect! end
Удаляет соединение из пула и разрывает его.
# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 389 def unprepared_statement cache = prepared_statements_disabled_cache.add?(object_id) if @prepared_statements yield ensure cache&.delete(object_id) end
# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 815
def verify!
unless active?
@lock.synchronize do
if @unconfigured_connection
attempt_configure_connection do
@raw_connection = @unconfigured_connection
@unconfigured_connection = nil
configure_connection
@last_activity = Process.clock_gettime(Process::CLOCK_MONOTONIC)
@verified = true
@allow_preconnect = true
end
return
end
reconnect!(restore_transactions: true)
end
end
@last_activity = Process.clock_gettime(Process::CLOCK_MONOTONIC)
@verified = true
end Проверяет, активно ли ещё соединение с базой данных (то есть не устарело ли оно). Для этого внутри вызывается active?. Если соединение больше не активно, этот метод повторно подключается к базе данных.
# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 225 def verify_timeout (@config[:verify_timeout] || 2).to_i end
Закрытые методы экземпляра
# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 1205
def log(sql, name = "SQL", binds = [], type_casted_binds = [], async: false, allow_retry: false, &block) # :doc:
instrumenter.instrument(
"sql.active_record",
sql: sql,
name: name,
binds: binds,
type_casted_binds: type_casted_binds,
async: async,
allow_retry: allow_retry,
connection: self,
transaction: current_transaction.user_transaction.presence,
affected_rows: 0,
row_count: 0,
&block
)
rescue ActiveRecord::StatementInvalid => ex
raise ex.set_query(sql, binds)
end
© 2004–2021 David Heinemeier Hansson
Licensed under the MIT License.