- A
- B
- C
- D
- E
- H
- I
- N
- R
- S
- T
- U
- W
类公共方法
new() 链接
来源: 显示 | 在 GitHub 上
# File activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb, line 6 def initialize super reset_transaction end
实例公共方法
add_transaction_record(record, ensure_finalize = true) 链接
将记录注册到当前事务中,以便调用其 after_commit 和 after_rollback 回调。
来源: 显示 | 在 GitHub 上
# File activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb, line 424 def add_transaction_record(record, ensure_finalize = true) current_transaction.add_record(record, ensure_finalize) end
begin_db_transaction() 链接
开始事务(并关闭自动提交)。
来源: 显示 | 在 GitHub 上
# File activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb, line 429 def begin_db_transaction() end
begin_isolated_db_transaction(isolation) 链接
开始具有已设置隔离级别的事务。默认情况下会引发错误;支持设置隔离级别的适配器应实现此方法。
来源: 显示 | 在 GitHub 上
# File activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb, line 454 def begin_isolated_db_transaction(isolation) raise ActiveRecord::TransactionIsolationError, "adapter does not support setting transaction isolation" end
commit_db_transaction() 链接
提交事务(并开启自动提交)。
来源: 显示 | 在 GitHub 上
# File activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb, line 468 def commit_db_transaction() end
create(arel, name = nil, pk = nil, id_value = nil, sequence_name = nil, binds = [], returning: nil) 链接
default_sequence_name(table, column) 链接
来源: 显示 | 在 GitHub 上
# File activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb, line 490 def default_sequence_name(table, column) nil end
delete(arel, name = nil, binds = []) 链接
执行 DELETE 语句并返回受影响的行数。
来源: 显示 | 在 GitHub 上
# File activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb, line 215 def delete(arel, name = nil, binds = []) sql, binds = to_sql_and_binds(arel, binds) exec_delete(sql, name, binds) end
empty_insert_statement_value(primary_key = nil) 链接
来源: 显示 | 在 GitHub 上
# File activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb, line 520 def empty_insert_statement_value(primary_key = nil) "DEFAULT VALUES" end
exec_delete(sql, name = nil, binds = []) 链接
在当前连接的上下文中执行 DELETE sql 语句,并使用 binds 作为绑定替换。name 将与执行的 sql 语句一起记录。
来源: 显示 | 在 GitHub 上
# File activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb, line 168 def exec_delete(sql, name = nil, binds = []) affected_rows(internal_execute(sql, name, binds)) end
exec_insert(sql, name = nil, binds = [], pk = nil, sequence_name = nil, returning: nil) 链接
在当前连接的上下文中执行 INSERT sql 语句,并使用 binds 作为绑定替换。name 将与执行的 sql 语句一起记录。某些适配器支持 ‘returning` 关键字参数,该参数允许控制查询的结果:`nil` 是默认值并保持默认行为。如果传递了列名数组,结果将包含插入行中指定列的值。
来源: 显示 | 在 GitHub 上
# File activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb, line 160 def exec_insert(sql, name = nil, binds = [], pk = nil, sequence_name = nil, returning: nil) sql, binds = sql_for_insert(sql, pk, binds, returning) internal_exec_query(sql, name, binds) end
exec_query(sql, name = "SQL", binds = [], prepare: false) 链接
在当前连接的上下文中执行 sql 语句,并使用 binds 作为绑定替换。name 将与执行的 sql 语句一起记录。
注意:假设查询具有副作用,并且查询缓存将被清除。如果查询是只读的,请考虑使用 select_all 而不是。
来源: 显示 | 在 GitHub 上
# File activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb, line 150 def exec_query(sql, name = "SQL", binds = [], prepare: false) internal_exec_query(sql, name, binds, prepare: prepare) end
exec_update(sql, name = nil, binds = []) 链接
在当前连接的上下文中执行 UPDATE sql 语句,并使用 binds 作为绑定替换。name 将与执行的 sql 语句一起记录。
来源: 显示 | 在 GitHub 上
# File activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb, line 175 def exec_update(sql, name = nil, binds = []) affected_rows(internal_execute(sql, name, binds)) end
execute(sql, name = nil, allow_retry: false) 链接
在当前连接的上下文中执行 SQL 语句,并从数据库适配器返回原始结果。
将 allow_retry 设置为 true 会导致数据库在发生与连接相关的异常时重新连接并重试执行 SQL 语句。此选项仅应为已知的幂等查询启用。
注意:假设查询具有副作用,并且查询缓存将被清除。如果查询是只读的,请考虑使用 select_all 而不是。
注意:根据您的数据库连接器,此方法返回的结果可能需要手动内存管理。请考虑使用 exec_query 包装器而不是。
来源: 显示 | 在 GitHub 上
# File activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb, line 139 def execute(sql, name = nil, allow_retry: false) internal_execute(sql, name, allow_retry: allow_retry) end
high_precision_current_timestamp() 链接
返回一个 Arel SQL 字面量 CURRENT_TIMESTAMP,用于与任意精度日期/时间列一起使用。
支持带精度的日期/时间列的适配器应重写此方法以提供尽可能高的精度。
来源: 显示 | 在 GitHub 上
# File activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb, line 544 def high_precision_current_timestamp HIGH_PRECISION_CURRENT_TIMESTAMP end
insert(arel, name = nil, pk = nil, id_value = nil, sequence_name = nil, binds = [], returning: nil) 链接
执行 INSERT 查询并返回新记录的 ID。
id_value 将被返回,除非值为 nil,在这种情况下,数据库将尝试计算最后插入的 id 并返回该值。
如果下一个 id 已预先计算(例如在 Oracle 中),则应将其作为 id_value 传递。某些适配器支持 ‘returning` 关键字参数,该参数允许定义方法的返回值:`nil` 是默认值并保持默认行为。如果传递了列名数组,则该方法将返回一个数组,该数组表示插入行中指定列的值。
来源: 显示 | 在 GitHub 上
# File activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb, line 198 def insert(arel, name = nil, pk = nil, id_value = nil, sequence_name = nil, binds = [], returning: nil) sql, binds = to_sql_and_binds(arel, binds) value = exec_insert(sql, name, binds, pk, sequence_name, returning: returning) return returning_column_values(value) unless returning.nil? id_value || last_inserted_id(value) end
insert_fixture(fixture, table_name) 链接
将给定的 fixture 插入表中。在需要比简单插入更复杂的操作的适配器中重写(例如 Oracle)。大多数适配器应实现 insert_fixtures_set,它利用批量 SQL 插入。我们保留此方法以提供对不支持批量插入的数据库(如 SQLite)的回退。
来源: 显示 | 在 GitHub 上
# File activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb, line 504 def insert_fixture(fixture, table_name) execute(build_fixture_sql(Array.wrap(fixture), table_name), "Fixture Insert") end
insert_fixtures_set(fixture_set, tables_to_delete = []) 链接
来源: 显示 | 在 GitHub 上
# File activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb, line 508 def insert_fixtures_set(fixture_set, tables_to_delete = []) fixture_inserts = build_fixture_statements(fixture_set) table_deletes = tables_to_delete.map { |table| "DELETE FROM #{quote_table_name(table)}" } statements = table_deletes + fixture_inserts transaction(requires_new: true) do disable_referential_integrity do execute_batch(statements, "Fixtures Load") end end end
reset_isolation_level() 链接
在隔离数据库事务提交或回滚后调用的钩子点。大多数适配器不需要实现任何内容,因为隔离级别是在每个事务的基础上设置的。但某些数据库(如 SQLite)在每个连接级别设置它,并且需要在提交或回滚后显式重置它。
来源: 显示 | 在 GitHub 上
# File activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb, line 464 def reset_isolation_level end
reset_sequence!(table, column, sequence = nil) 链接
将序列设置为表列的最大值。
来源: 显示 | 在 GitHub 上
# File activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb, line 495 def reset_sequence!(table, column, sequence = nil) # Do nothing by default. Implement for PostgreSQL, Oracle, ... end
restart_db_transaction() 链接
来源: 显示 | 在 GitHub 上
# File activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb, line 480 def restart_db_transaction exec_restart_db_transaction end
rollback_db_transaction() 链接
回滚事务(并开启自动提交)。如果事务块引发异常或返回 false,则必须执行此操作。
来源: 显示 | 在 GitHub 上
# File activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb, line 472 def rollback_db_transaction exec_rollback_db_transaction rescue ActiveRecord::ConnectionNotEstablished, ActiveRecord::ConnectionFailed # Connection's gone; that counts as a rollback end
rollback_to_savepoint(name = nil) 链接
来源: 显示 | 在 GitHub 上
# File activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb, line 486 def rollback_to_savepoint(name = nil) exec_rollback_to_savepoint(name) end
select_all(arel, name = nil, binds = [], preparable: nil, async: false, allow_retry: false) 链接
返回一个 ActiveRecord::Result 实例。
来源: 显示 | 在 GitHub 上
# File activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb, line 72 def select_all(arel, name = nil, binds = [], preparable: nil, async: false, allow_retry: false) arel = arel_from_relation(arel) sql, binds, preparable, allow_retry = to_sql_and_binds(arel, binds, preparable, allow_retry) select(sql, name, binds, prepare: prepared_statements && preparable, async: async && FutureResult::SelectAll, allow_retry: allow_retry ) rescue ::RangeError ActiveRecord::Result.empty(async: async) end
select_one(arel, name = nil, binds = [], async: false) 链接
返回一个记录哈希,其中键是列名,值是列值。
来源: 显示 | 在 GitHub 上
# File activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb, line 87 def select_one(arel, name = nil, binds = [], async: false) select_all(arel, name, binds, async: async).then(&:first) end
select_rows(arel, name = nil, binds = [], async: false) 链接
返回一个包含字段值的数组。顺序与 columns 返回的顺序相同。
来源: 显示 | 在 GitHub 上
# File activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb, line 104 def select_rows(arel, name = nil, binds = [], async: false) select_all(arel, name, binds, async: async).then(&:rows) end
select_value(arel, name = nil, binds = [], async: false) 链接
从记录中返回单个值。
来源: 显示 | 在 GitHub 上
# File activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb, line 92 def select_value(arel, name = nil, binds = [], async: false) select_rows(arel, name, binds, async: async).then { |rows| single_value_from_rows(rows) } end
select_values(arel, name = nil, binds = []) 链接
返回 SELECT 查询第一列值的一个数组。
select_values("SELECT id FROM companies LIMIT 3") => [1,2,3]
来源: 显示 | 在 GitHub 上
# File activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb, line 98 def select_values(arel, name = nil, binds = []) select_rows(arel, name, binds).map(&:first) end
to_sql(arel_or_sql_string, binds = []) 链接
将 arel AST 转换为 SQL。
来源: 显示 | 在 GitHub 上
# File activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb, line 12 def to_sql(arel_or_sql_string, binds = []) sql, _ = to_sql_and_binds(arel_or_sql_string, binds) sql end
transaction(requires_new: nil, isolation: nil, &block) 链接
在数据库事务中运行给定的块,并返回块的结果。
Transaction 回调¶ ↑
transaction 块会产生一个 ActiveRecord::Transaction 对象,可以在其上注册回调。
ActiveRecord::Base.transaction do |transaction| transaction.before_commit { puts "before commit!" } transaction.after_commit { puts "after commit!" } transaction.after_rollback { puts "after rollback!" } end
嵌套事务支持¶ ↑
transaction 调用可以嵌套。默认情况下,这会将嵌套事务块中的所有数据库语句添加到父事务中。例如,以下行为可能会令人惊讶:
ActiveRecord::Base.transaction do Post.create(title: 'first') ActiveRecord::Base.transaction do Post.create(title: 'second') raise ActiveRecord::Rollback end end
这会创建“first”和“second”两个帖子。原因是嵌套块中的 ActiveRecord::Rollback 异常不会发出 ROLLBACK。由于这些异常在事务块中捕获,父块看不到它们,实际事务会被提交。
大多数数据库不支持真正的嵌套事务。在撰写本文时,我们所知的唯一支持真正嵌套事务的数据库是 MS-SQL。
为了解决这个问题,transaction 将使用保存点来模拟嵌套事务的效果:dev.mysql.com/doc/refman/en/savepoint.html。
如果数据库事务已打开,则调用此方法是安全的,即如果 transaction 在另一个 transaction 块内调用。在这种嵌套调用的情况下,transaction 的行为如下:
-
块将在不执行任何操作的情况下运行。块中的所有数据库语句都将有效地附加到已打开的数据库事务中。
-
但是,如果设置了
:requires_new,则块将被包装在充当子事务的数据库保存点中。
为了使嵌套事务回滚,您可以通过传递 requires_new: true 来请求真正的子事务。如果出现任何问题,数据库将回滚到子事务的开头,而不会回滚父事务。如果我们将其添加到前面的示例中:
ActiveRecord::Base.transaction do Post.create(title: 'first') ActiveRecord::Base.transaction(requires_new: true) do Post.create(title: 'second') raise ActiveRecord::Rollback end end
只创建标题为“first”的帖子。
有关更多信息,请参阅 ActiveRecord::Transactions。
注意事项¶ ↑
MySQL 不支持 DDL 事务。如果您执行了 DDL 操作,则所有创建的保存点都将被自动释放。例如,如果您创建了一个保存点,然后执行了一个 CREATE TABLE 语句,那么创建的保存点将被自动释放。
这意味着,在 MySQL 上,您不应在可能创建保存点的 transaction 调用中执行 DDL 操作。否则,当 transaction 尝试释放已自动释放的保存点时,将引发异常。
Model.lease_connection.transaction do # BEGIN
Model.lease_connection.transaction(requires_new: true) do # CREATE SAVEPOINT active_record_1
Model.lease_connection.create_table(...)
# active_record_1 now automatically released
end # RELEASE SAVEPOINT active_record_1 <--- BOOM! database error!
end
Transaction 隔离¶ ↑
如果您的数据库支持为事务设置隔离级别,则可以这样做:
Post.transaction(isolation: :serializable) do # ... end
有效的隔离级别有:
-
:read_uncommitted -
:read_committed -
:repeatable_read -
:serializable
您应该查阅您的数据库文档,以了解这些不同级别的语义。
如果出现以下情况,将引发 ActiveRecord::TransactionIsolationError:
-
适配器不支持设置隔离级别。
-
您正在加入一个现有的打开事务。
-
您正在创建一个嵌套(保存点)事务。
mysql2、trilogy 和 postgresql 适配器支持设置事务隔离级别。
来源: 显示 | 在 GitHub 上
# File activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb, line 355 def transaction(requires_new: nil, isolation: nil, joinable: true, &block) # If we're running inside the single, non-joinable transaction that # ActiveRecord::TestFixtures starts around each example (depth == 1), # an `isolation:` hint must be validated then ignored so that the # adapter isn't asked to change the isolation level mid-transaction. if isolation && !requires_new && open_transactions == 1 && !current_transaction.joinable? iso = isolation.to_sym unless transaction_isolation_levels.include?(iso) raise ActiveRecord::TransactionIsolationError, "invalid transaction isolation level: #{iso.inspect}" end current_transaction.isolation = iso isolation = nil end if !requires_new && current_transaction.joinable? if isolation && current_transaction.isolation != isolation raise ActiveRecord::TransactionIsolationError, "cannot set isolation when joining a transaction" end yield current_transaction.user_transaction else within_new_transaction(isolation: isolation, joinable: joinable, &block) end rescue ActiveRecord::Rollback # rollbacks are silently swallowed end
transaction_isolation_levels() 链接
来源: 显示 | 在 GitHub 上
# File activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb, line 447 def transaction_isolation_levels TRANSACTION_ISOLATION_LEVELS end
transaction_open?() 链接
来源: 显示 | 在 GitHub 上
# File activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb, line 398 def transaction_open? current_transaction.open? end
truncate(table_name, name = nil) 链接
执行 TRUNCATE 语句。
来源: 显示 | 在 GitHub 上
# File activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb, line 221 def truncate(table_name, name = nil) execute(build_truncate_statement(table_name), name) end
update(arel, name = nil, binds = []) 链接
执行 UPDATE 语句并返回受影响的行数。
来源: 显示 | 在 GitHub 上
# File activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb, line 209 def update(arel, name = nil, binds = []) sql, binds = to_sql_and_binds(arel, binds) exec_update(sql, name, binds) end
write_query?(sql) 链接
确定 SQL 语句是否为写查询。
来源: 显示 | 在 GitHub 上
# File activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb, line 121 def write_query?(sql) raise NotImplementedError end