Spec-Zone.ru › Ruby on Rails 5.1

module ActiveRecord::ConnectionAdapters::DatabaseStatements

Открытые методы класса

new() Show source
# File activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb, line 4
def initialize
  super
  reset_transaction
end
Вызывает метод суперкласса

Открытые методы экземпляра

add_transaction_record(record) Show source
# File activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb, line 255
def add_transaction_record(record)
  current_transaction.add_record(record)
end

Регистрирует запись в текущей транзакции, чтобы можно было вызвать её обратные вызовы after_commit и after_rollback.

begin_db_transaction() Show source
# File activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb, line 264
def begin_db_transaction()    end

Начинает транзакцию (и отключает автоматическую фиксацию).

begin_isolated_db_transaction(isolation) Show source
# File activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb, line 278
def begin_isolated_db_transaction(isolation)
  raise ActiveRecord::TransactionIsolationError, "adapter does not support setting transaction isolation"
end

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

commit_db_transaction() Show source
# File activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb, line 283
def commit_db_transaction()   end

Фиксирует транзакцию (и включает автоматическую фиксацию).

create(arel, name = nil, pk = nil, id_value = nil, sequence_name = nil, binds = [])
Псевдоним для: insert
delete(arel, name = nil, binds = []) Show source
# File activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb, line 144
def delete(arel, name = nil, binds = [])
  exec_delete(to_sql(arel, binds), name, binds)
end

Выполняет оператор delete и возвращает количество затронутых строк.

exec_delete(sql, name = nil, binds = []) Show source
# File activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb, line 108
def exec_delete(sql, name = nil, binds = [])
  exec_query(sql, name, binds)
end

Выполняет оператор delete sql в контексте этого соединения, используя binds в качестве заменителей привязки. name регистрируется вместе с выполненным оператором sql.

exec_insert(sql, name = nil, binds = [], pk = nil, sequence_name = nil) Show source
# File activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb, line 100
def exec_insert(sql, name = nil, binds = [], pk = nil, sequence_name = nil)
  sql, binds = sql_for_insert(sql, pk, nil, sequence_name, binds)
  exec_query(sql, name, binds)
end

Выполняет оператор insert sql в контексте этого соединения, используя binds в качестве заменителей привязки. name регистрируется вместе с выполненным оператором sql.

exec_query(sql, name = "SQL", binds = [], prepare: false) Show source
# File activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb, line 93
def exec_query(sql, name = "SQL", binds = [], prepare: false)
  raise NotImplementedError
end

Выполняет оператор sql в контексте этого соединения, используя binds в качестве заменителей привязки. name регистрируется вместе с выполненным оператором sql.

exec_update(sql, name = nil, binds = []) Show source
# File activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb, line 120
def exec_update(sql, name = nil, binds = [])
  exec_query(sql, name, binds)
end

Выполняет оператор update sql в контексте этого соединения, используя binds в качестве заменителей привязки. name регистрируется вместе с выполненным оператором sql.

execute(sql, name = nil) Show source
# File activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb, line 86
def execute(sql, name = nil)
  raise NotImplementedError
end

Выполняет SQL-запрос в контексте этого соединения и возвращает необработанный результат из адаптера соединения. Примечание: в зависимости от вашего средства подключения к базе данных, результат, возвращаемый этим методом, может управляться вручную в памяти. Рассмотрите возможность использования обертки #exec_query вместо этого.

insert(arel, name = nil, pk = nil, id_value = nil, sequence_name = nil, binds = []) Show source
# File activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb, line 132
def insert(arel, name = nil, pk = nil, id_value = nil, sequence_name = nil, binds = [])
  value = exec_insert(to_sql(arel, binds), name, binds, pk, sequence_name)
  id_value || last_inserted_id(value)
end

Выполняет запрос INSERT и возвращает ID новой записи

id_value будет возвращено, если значение не равно nil, в этом случае база данных попытается вычислить последний вставленный ID и вернуть это значение.

Если следующий ID был вычислен заранее (как в Oracle), его следует передать как id_value.

Также известен как: create
rollback_db_transaction() Show source
# File activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb, line 287
def rollback_db_transaction
  exec_rollback_db_transaction
end

Откатывает транзакцию (и включает автоматическую фиксацию). Необходимо сделать, если блок транзакции вызывает исключение или возвращает false.

select_all(arel, name = nil, binds = [], preparable: nil) Show source
# File activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb, line 31
def select_all(arel, name = nil, binds = [], preparable: nil)
  arel, binds = binds_from_relation arel, binds
  sql = to_sql(arel, binds)
  if !prepared_statements || (arel.is_a?(String) && preparable.nil?)
    preparable = false
  else
    preparable = visitor.preparable
  end
  if prepared_statements && preparable
    select_prepared(sql, name, binds)
  else
    select(sql, name, binds)
  end
end

Возвращает экземпляр ActiveRecord::Result.

select_one(arel, name = nil, binds = []) Show source
# File activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb, line 48
def select_one(arel, name = nil, binds = [])
  select_all(arel, name, binds).first
end

Возвращает хэш записи с именами столбцов в качестве ключей и значениями столбцов в качестве значений.

select_rows(arel, name = nil, binds = []) Show source
# File activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb, line 65
def select_rows(arel, name = nil, binds = [])
  select_all(arel, name, binds).rows
end

Возвращает массив массивов, содержащих значения полей. Порядок такой же, как и возвращаемый columns.

select_value(arel, name = nil, binds = []) Show source
# File activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb, line 53
def select_value(arel, name = nil, binds = [])
  single_value_from_rows(select_rows(arel, name, binds))
end

Возвращает одно значение из записи

select_values(arel, name = nil, binds = []) Show source
# File activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb, line 59
def select_values(arel, name = nil, binds = [])
  select_rows(arel, name, binds).map(&:first)
end

Возвращает массив значений первого столбца в select:

select_values("SELECT id FROM companies LIMIT 3") => [1,2,3]
supports_statement_cache?() Show source
# File activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb, line 150
def supports_statement_cache?
  false
end

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

to_sql(arel, binds = []) Show source
# File activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb, line 10
def to_sql(arel, binds = [])
  if arel.respond_to?(:ast)
    collected = visitor.accept(arel.ast, collector)
    collected.compile(binds, self).freeze
  else
    arel.dup.freeze
  end
end

Преобразует AST arel в SQL

transaction(requires_new: nil, isolation: nil, joinable: true) { || ... } Показать исходный код
# File activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb, line 228
def transaction(requires_new: nil, isolation: nil, joinable: true)
  if !requires_new && current_transaction.joinable?
    if isolation
      raise ActiveRecord::TransactionIsolationError, "cannot set isolation when joining a transaction"
    end
    yield
  else
    transaction_manager.within_new_transaction(isolation: isolation, joinable: joinable) { yield }
  end
rescue ActiveRecord::Rollback
  # rollbacks are silently swallowed
end

Выполняет заданный блок в транзакции базы данных и возвращает результат блока.

Поддержка вложенных транзакций

Большинство баз данных не поддерживают истинные вложенные транзакции. На момент написания, единственная база данных, о которой нам известно, поддерживающая истинные вложенные транзакции — это MS-SQL.

Для решения этой проблемы, transaction эмулирует эффект вложенных транзакций, используя точки сохранения: dev.mysql.com/doc/refman/5.7/en/savepoint.html Точки сохранения поддерживаются MySQL и PostgreSQL. SQLite3 версии >= '3.6.8' поддерживает точки сохранения.

Этот метод безопасно вызывать, если транзакция базы данных уже открыта, т. е. если transaction вызывается внутри другого блока transaction. В случае вложенного вызова transaction будет вести себя следующим образом:

  • Блок будет выполнен без каких-либо действий. Все операторы базы данных, выполняемые в блоке, фактически добавляются к уже открытой транзакции базы данных.

  • Однако, если :requires_new установлено, блок будет заключён в точку сохранения базы данных, выступающую в качестве подтранзакции.

Ограничения

MySQL не поддерживает транзакции DDL. Если вы выполните операцию DDL, то все созданные точки сохранения будут автоматически освобождены. Например, если вы создали точку сохранения, затем выполнили оператор CREATE TABLE, то созданная точка сохранения будет автоматически освобождена.

Это означает, что в MySQL не следует выполнять операции DDL внутри вызова transaction, который, как вы знаете, может создать точку сохранения. В противном случае, transaction будет генерировать исключения при попытке освободить уже автоматически освобожденные точки сохранения:

Model.connection.transaction do  # BEGIN
  Model.connection.transaction(requires_new: true) do  # CREATE SAVEPOINT active_record_1
    Model.connection.create_table(...)
    # active_record_1 now automatically released
  end  # RELEASE SAVEPOINT active_record_1  <--- BOOM! database error!
end

Изоляция транзакций

Если ваша база данных поддерживает установку уровня изоляции для транзакции, вы можете установить его следующим образом:

Post.transaction(isolation: :serializable) do
  # ...
end

Допустимые уровни изоляции:

  • :read_uncommitted

  • :read_committed

  • :repeatable_read

  • :serializable

Обратитесь к документации вашей базы данных, чтобы понять семантику этих различных уровней:

  • www.postgresql.org/docs/current/static/transaction-iso.html

  • dev.mysql.com/doc/refman/5.7/en/set-transaction.html

Исключение ActiveRecord::TransactionIsolationError будет возбуждено, если:

  • Адаптер не поддерживает установку уровня изоляции

  • Вы присоединяетесь к уже открытой транзакции

  • Вы создаёте вложенную (с точкой сохранения) транзакцию

Адаптеры mysql2 и postgresql поддерживают установку уровня изоляции транзакции.

transaction_isolation_levels() Показать исходный код
# File activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb, line 266
def transaction_isolation_levels
  {
    read_uncommitted: "READ UNCOMMITTED",
    read_committed:   "READ COMMITTED",
    repeatable_read:  "REPEATABLE READ",
    serializable:     "SERIALIZABLE"
  }
end
transaction_open?() Показать исходный код
# File activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb, line 245
def transaction_open?
  current_transaction.open?
end
transaction_state() Показать исходный код
# File activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb, line 259
def transaction_state
  current_transaction.state
end
truncate(table_name, name = nil) Показать исходный код
# File activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb, line 113
def truncate(table_name, name = nil)
  raise NotImplementedError
end

Выполняет оператор truncate.

update(arel, name = nil, binds = []) Показать исходный код
# File activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb, line 139
def update(arel, name = nil, binds = [])
  exec_update(to_sql(arel, binds), name, binds)
end

Выполняет оператор update и возвращает количество затронутых строк.

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

Spec-Zone.ru

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