跳至內容 跳至搜尋

Active Record 抽象介面

Active Record 支援多個資料庫系統。 AbstractAdapter 與相關類別形成抽象層,讓這件事成為可能。 AbstractAdapter 代表與資料庫的連線,並提供資料庫特定功能的抽象介面,例如建立連線、跳脫值、為 :offset:limit 選項建立正確的 SQL 片段等。

所有具體的資料庫介面都遵循此類別中制定的介面。 ActiveRecord::Base.connection 會傳回 AbstractAdapter 物件,你可以使用它。

介面中的大部分方法在遷移期間都很有用。最值得注意的是, SchemaStatements 提供的實例方法非常有用。

命名空間
方法
A
C
D
E
F
I
L
P
R
S
T
U
V
已包含模組

常數

ADAPTER_NAME = "Abstract"
 
COMMENT_REGEX = %r{(?:--.*\n)|/\*(?:[^*]|\*[^/])*\*/}
 
EXTENDED_TYPE_MAPS = Concurrent::Map.new
 
SIMPLE_INT = /\A\d+\z/
 
TYPE_MAP = Type::TypeMap.new.tap { |m| initialize_type_map(m) }
 

屬性

[R] in_use?
[R] lock
[R] logger
[R] owner
[R] pool
[R] visitor

類別公開方法

database_exists?(config)

此轉接器的資料庫是否存在?

# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 382
def self.database_exists?(config)
  new(config).database_exists?
end

dbconsole(config, options = {})

開啟資料庫主控台工作階段。

# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 124
def self.dbconsole(config, options = {})
  raise NotImplementedError
end

find_cmd_and_exec(commands, *args)

# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 95
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

type_cast_config_to_boolean(config)

# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 68
def self.type_cast_config_to_boolean(config)
  if config == "false"
    false
  else
    config
  end
end

type_cast_config_to_integer(config)

# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 58
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

validate_default_timezone(config)

# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 76
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

實例公開方法

active?()

檢查與資料庫的連線是否仍然有效。這包括檢查資料庫是否實際上能夠回應,也就是連線是否沒有過期。

# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 674
def active?
end

adapter_name()

傳回轉接器的可讀名稱。使用混合大小寫 - 如果需要,隨時可以使用小寫。

# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 377
def adapter_name
  self.class::ADAPTER_NAME
end

all_foreign_keys_valid?()

覆寫以檢查資料庫中的所有外來鍵約束。

# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 655
def all_foreign_keys_valid?
  check_all_foreign_keys_valid!
  true
rescue ActiveRecord::StatementInvalid
  false
end

check_all_foreign_keys_valid!()

覆寫以檢查資料庫中的所有外來鍵約束。如果外來鍵約束未滿足,轉接器應引發 ActiveRecord::StatementInvalid

# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 666
def check_all_foreign_keys_valid!
end

clear_cache!(new_connection: false)

清除資料庫轉接器可能執行的任何快取。

# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 754
def clear_cache!(new_connection: false)
  if @statements
    @lock.synchronize do
      if new_connection
        @statements.reset
      else
        @statements.clear
      end
    end
  end
end

close()

將連線檢查回連線池

# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 846
def close
  pool.checkin self
end

connect!()

# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 794
def connect!
  verify!
  self
end

connection_retries()

# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 222
def connection_retries
  (@config[:connection_retries] || 1).to_i
end

database_exists?()

# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 386
def database_exists?
  connect!
  true
rescue ActiveRecord::NoDatabaseError
  false
end

default_timezone()

# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 234
def default_timezone
  @default_timezone || ActiveRecord.default_timezone
end

disable_extension(name, **)

這是由支援擴充功能的介面所實作

# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 592
def disable_extension(name, **)
end

disable_referential_integrity()

覆寫以關閉參照完整性,同時執行 &block

# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 650
def disable_referential_integrity
  yield
end

discard!()

立即忘記此連線曾經存在過。與 disconnect! 不同,這不會與伺服器通訊。

呼叫此方法後,所有其他方法的行為將變得未定義。在分岔處理程序擺脫屬於其父項目的連線之前,會在內部呼叫此方法。

# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 729
def discard!
  # This should be overridden by concrete adapters.
end

disconnect!()

如果已連線,則與資料庫斷開連線。否則,此方法不執行任何動作。

# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 717
def disconnect!
  clear_cache!(new_connection: true)
  reset_transaction
  @raw_connection_dirty = false
end

enable_extension(name, **)

這是由支援擴充功能的介面所實作

# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 596
def enable_extension(name, **)
end

expire()

此方法只能在持有連線池的 mutex 時呼叫

# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 334
def expire
  if in_use?
    if @owner != ActiveSupport::IsolatedExecutionState.context
      raise ActiveRecordError, "Cannot expire connection, " \
        "it is owned by a different thread: #{@owner}. " \
        "Current thread: #{ActiveSupport::IsolatedExecutionState.context}."
    end

    @idle_since = Process.clock_gettime(Process::CLOCK_MONOTONIC)
    @owner = nil
  else
    raise ActiveRecordError, "Cannot expire connection, it is not currently leased."
  end
end

extensions()

擴充功能清單,由支援它們的介面卡填入。

# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 638
def extensions
  []
end

index_algorithms()

索引演算法清單,由支援它們的介面卡填入。

# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 643
def index_algorithms
  {}
end

lease()

此方法只能在持有連線池的 mutex 時呼叫

# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 298
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

pool=(value)

# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 48
def pool=(value)
  return if value.eql?(@pool)
  @schema_cache = nil
  @pool = value

  @pool.schema_reflection.load!(self) if ActiveRecord.lazily_load_schema_cache
end

prefetch_primary_key?(table_name = nil)

是否應在插入陳述式之前從其對應的順序中選取主鍵值?如果為 true,則在每次插入之前呼叫 next_sequence_value 以設定記錄的主鍵。

# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 426
def prefetch_primary_key?(table_name = nil)
  false
end

prepared_statements()

別名為:prepared_statements?

prepared_statements?()

別名為:prepared_statements
# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 265
def prepared_statements?
  @prepared_statements && !prepared_statements_disabled_cache.include?(object_id)
end

preventing_writes?()

判斷是否目前正在防止寫入。

如果連線是複製品,或傳回 current_preventing_writes 的值,則傳回 true。

# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 242
def preventing_writes?
  return true if replica?
  return false if connection_class.nil?

  connection_class.current_preventing_writes
end

raw_connection()

提供存取此轉接器的底層資料庫驅動程式。例如,此方法在 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 814
def raw_connection
  with_raw_connection do |conn|
    disable_lazy_transactions!
    @raw_connection_dirty = true
    conn
  end
end

reconnect!(restore_transactions: false)

如果已連線,則中斷與資料庫的連線,並建立與資料庫的新連線。實作人員應該定義私有的 reconnect。

# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 680
def reconnect!(restore_transactions: false)
  retries_available = connection_retries
  deadline = retry_deadline && Process.clock_gettime(Process::CLOCK_MONOTONIC) + retry_deadline

  @lock.synchronize do
    reconnect

    enable_lazy_transactions!
    @raw_connection_dirty = false
    @verified = 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

    @verified = false

    raise translated_exception
  end
end

replica?()

# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 214
def replica?
  @config[:replica] || false
end

requires_reloading?()

如果開發模式需要重新載入要求之間的連線,則傳回 true。

# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 767
def requires_reloading?
  false
end

reset!()

重設此連線的狀態,指示 DBMS 清除交易和其他與連線相關的伺服器端狀態。通常是與資料庫相關的作業。

如果資料庫驅動程式或通訊協定不支援此功能,實作人員可能會將此別名設為 reconnect!。否則,實作人員應在重設連線後 (且在仍持有 @lock 時) 立即呼叫 super。

# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 741
def reset!
  clear_cache!(new_connection: true)
  reset_transaction
  configure_connection
end

retry_deadline()

# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 226
def retry_deadline
  if @config[:retry_deadline]
    @config[:retry_deadline].to_f
  else
    nil
  end
end

role()

目前連線的角色 (例如 :writing)。在非多重角色的應用程式中,會傳回 :writing

# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 319
def role
  @pool.role
end

savepoint_errors_invalidate_transactions?()

儲存點上的 TransactionRollbackErrors 是否會影響父交易?

# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 410
def savepoint_errors_invalidate_transactions?
  false
end

schema_cache()

# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 329
def schema_cache
  @schema_cache ||= BoundSchemaReflection.new(@pool.schema_reflection, self)
end

schema_version()

傳回資料庫中目前可用的架構版本識別碼。這通常等於已執行的最高編號遷移的數字,或者如果沒有架構資訊 / 資料庫為空,則為 0。

# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 881
def schema_version
  migration_context.current_version
end

shard()

目前連線的分片(例如::default)。在非分片應用程式中,會傳回 :default

# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 325
def shard
  @pool.shard
end

supports_advisory_locks?()

這個轉接器是否支援應用程式強制執行的建議鎖定?

# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 419
def supports_advisory_locks?
  false
end

supports_bulk_alter?()

# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 399
def supports_bulk_alter?
  false
end

supports_check_constraints?()

這個轉接器是否支援建立檢查約束?

# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 491
def supports_check_constraints?
  false
end

supports_comments?()

此配接器是否支援資料庫物件(表格、欄位、索引)的元資料註解?

# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 526
def supports_comments?
  false
end

supports_comments_in_create?()

表格、欄位和索引的註解是否可以在建立/變更表格陳述中指定?

# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 531
def supports_comments_in_create?
  false
end

supports_common_table_expressions?()

# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 550
def supports_common_table_expressions?
  false
end

supports_concurrent_connections?()

# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 574
def supports_concurrent_connections?
  true
end

supports_datetime_with_precision?()

此配接器是否支援帶有精度的日期時間?

# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 516
def supports_datetime_with_precision?
  false
end

supports_ddl_transactions?()

此配接器是否支援交易中的 DDL 回復?也就是說,CREATE TABLE 或 ALTER TABLE 是否會被交易回復?

# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 395
def supports_ddl_transactions?
  false
end

supports_deferrable_constraints?()

此轉接器是否支援建立可延遲的約束?

# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 486
def supports_deferrable_constraints?
  false
end

supports_exclusion_constraints?()

此轉接器是否支援建立排除約束?

# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 496
def supports_exclusion_constraints?
  false
end

supports_explain?()

此轉接器是否支援說明?

# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 455
def supports_explain?
  false
end

supports_expression_index?()

此轉接器是否支援表達式索引?

# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 450
def supports_expression_index?
  false
end

supports_extensions?()

此轉接器是否支援資料庫擴充功能?

# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 465
def supports_extensions?
  false
end

supports_foreign_keys?()

此轉接器是否支援建立外來鍵約束?

# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 476
def supports_foreign_keys?
  false
end

supports_foreign_tables?()

此轉接器是否支援外部/外部表格?

# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 541
def supports_foreign_tables?
  false
end

supports_index_include?()

此轉接器是否支援包含非主要欄位?

# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 445
def supports_index_include?
  false
end

supports_index_sort_order?()

此轉接器是否支援索引排序順序?

# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 435
def supports_index_sort_order?
  false
end

supports_indexes_in_create?()

此轉接器是否支援在建立表格的相同陳述中建立索引?

# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 471
def supports_indexes_in_create?
  false
end

supports_insert_conflict_target?()

# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 570
def supports_insert_conflict_target?
  false
end

supports_insert_on_duplicate_skip?()

# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 562
def supports_insert_on_duplicate_skip?
  false
end

supports_insert_on_duplicate_update?()

# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 566
def supports_insert_on_duplicate_update?
  false
end

supports_insert_returning?()

# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 558
def supports_insert_returning?
  false
end

supports_json?()

此轉接器是否支援 JSON 資料類型?

# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 521
def supports_json?
  false
end

supports_lazy_transactions?()

# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 554
def supports_lazy_transactions?
  false
end

supports_materialized_views?()

此轉接器是否支援實體化檢視?

# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 511
def supports_materialized_views?
  false
end

supports_nulls_not_distinct?()

# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 578
def supports_nulls_not_distinct?
  false
end

supports_optimizer_hints?()

此轉接器是否支援最佳化提示?

# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 546
def supports_optimizer_hints?
  false
end

supports_partial_index?()

這個配接器是否支援部分索引?

# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 440
def supports_partial_index?
  false
end

supports_partitioned_indexes?()

# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 430
def supports_partitioned_indexes?
  false
end

supports_restart_db_transaction?()

# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 414
def supports_restart_db_transaction?
  false
end

supports_savepoints?()

這個配接器是否支援儲存點?

# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 404
def supports_savepoints?
  false
end

supports_transaction_isolation?()

這個配接器是否支援設定交易的隔離層級?

# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 460
def supports_transaction_isolation?
  false
end

supports_unique_constraints?()

此轉接器是否支援建立唯一約束?

# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 501
def supports_unique_constraints?
  false
end

supports_validate_constraints?()

此轉接器是否支援建立無效約束?

# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 481
def supports_validate_constraints?
  false
end

supports_views?()

此轉接器是否支援檢視?

# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 506
def supports_views?
  false
end

supports_virtual_columns?()

此轉接器是否支援虛擬欄位?

# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 536
def supports_virtual_columns?
  false
end

throw_away!()

從池中移除連線並斷開連線。

# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 748
def throw_away!
  pool.remove self
  disconnect!
end

unprepared_statement()

# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 368
def unprepared_statement
  cache = prepared_statements_disabled_cache.add?(object_id) if @prepared_statements
  yield
ensure
  cache&.delete(object_id)
end

use_metadata_table?()

# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 218
def use_metadata_table?
  @config.fetch(:use_metadata_table, true)
end

verify!()

檢查與資料庫的連線是否仍為有效(即非過期)。這會在幕後呼叫 active? 來執行。如果連線不再有效,則此方法會重新連線至資料庫。

# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 774
def verify!
  unless active?
    if @unconfigured_connection
      @lock.synchronize do
        if @unconfigured_connection
          @raw_connection = @unconfigured_connection
          @unconfigured_connection = nil
          configure_connection
          @verified = true
          return
        end
      end
    end

    reconnect!(restore_transactions: true)
  end

  @verified = true
end

實例私有方法

log(sql, name = "SQL", binds = [], type_casted_binds = [], statement_name = nil, async: false, &block)

# File activerecord/lib/active_record/connection_adapters/abstract_adapter.rb, line 1142
def log(sql, name = "SQL", binds = [], type_casted_binds = [], statement_name = nil, async: false, &block) # :doc:
  @instrumenter.instrument(
    "sql.active_record",
    sql:               sql,
    name:              name,
    binds:             binds,
    type_casted_binds: type_casted_binds,
    statement_name:    statement_name,
    async:             async,
    connection:        self,
    &block
  )
rescue ActiveRecord::StatementInvalid => ex
  raise ex.set_query(sql, binds)
end