- A
- B
- C
- D
- E
- H
- I
- N
- R
- S
- T
- U
- W
类公开方法
new() 链接
实例公开方法
add_transaction_record(record, ensure_finalize = true) 链接
将记录注册到当前事务中,以便可以在其 after_commit 和 after_rollback 回调中调用该记录。
begin_db_transaction() 链接
开始事务(并关闭自动提交)。
begin_isolated_db_transaction(isolation) 链接
以设置的隔离级别开始事务。默认情况下会引发错误;支持设置隔离级别的适配器应该实现此方法。
commit_db_transaction() 链接
提交事务(并打开自动提交)。
create(arel, name = nil, pk = nil, id_value = nil, sequence_name = nil, binds = [], returning: nil) 链接
default_sequence_name(table, column) 链接
delete(arel, name = nil, binds = []) 链接
执行删除语句并返回受影响的行数。
empty_insert_statement_value(primary_key = nil) 链接
exec_delete(sql, name = nil, binds = []) 链接
使用binds
作为绑定替换,在当前连接的上下文中执行删除sql
语句。name
与执行的sql
语句一起记录。
exec_insert(sql, name = nil, binds = [], pk = nil, sequence_name = nil, returning: nil) 链接
使用binds
作为绑定替换,在当前连接的上下文中执行插入sql
语句。name
与执行的sql
语句一起记录。某些适配器支持“returning”关键字参数,该参数允许控制查询的结果:nil
是默认值并保持默认行为。如果传递了列名数组 - 结果将包含插入行中指定列的值。
# File activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb, line 157 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) 链接
使用binds
作为绑定替换,在当前连接的上下文中执行sql
语句。name
与执行的sql
语句一起记录。
注意:假设查询具有副作用,并且将清除查询缓存。如果查询是只读的,请考虑使用 select_all
而不是。
exec_update(sql, name = nil, binds = []) 链接
使用binds
作为绑定替换,在当前连接的上下文中执行更新sql
语句。name
与执行的sql
语句一起记录。
execute(sql, name = nil, allow_retry: false) 链接
在当前连接的上下文中执行 SQL 语句,并返回来自连接适配器的原始结果。
将allow_retry
设置为 true 会导致数据库重新连接并在出现与连接相关的异常时重试执行 SQL 语句。此选项应仅在已知幂等查询的情况下启用。
注意:假设查询具有副作用,并且将清除查询缓存。如果查询是只读的,请考虑使用 select_all
而不是。
注意:根据您的数据库连接器,此方法返回的结果可能需要手动进行内存管理。请考虑使用 exec_query
包装器。
high_precision_current_timestamp() 链接
返回用于具有任意精度的日期/时间列的 Arel
SQL 文字的 CURRENT_TIMESTAMP。
支持具有精度的日期时间的适配器应覆盖此方法以提供尽可能多的精度。
insert(arel, name = nil, pk = nil, id_value = nil, sequence_name = nil, binds = [], returning: nil) 链接
执行 INSERT 查询并返回新记录的 ID
除非值为nil
,否则将返回id_value
,在这种情况下,数据库将尝试计算最后插入的 id 并返回该值。
如果提前计算了下一个 id(如在 Oracle 中),则应将其作为id_value
传递。某些适配器支持“returning”关键字参数,该参数允许定义方法的返回值:nil
是默认值并保持默认行为。如果传递了列名数组 - 从方法返回一个数组,表示插入行中指定列的值。
# File activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb, line 195 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 482 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 486 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 442 def reset_isolation_level end
reset_sequence!(table, column, sequence = nil) 链接
将序列设置为表列的最大值。
来源:显示 | 在 GitHub 上
# File activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb, line 473 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 458 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 450 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 464 def rollback_to_savepoint(name = nil) exec_rollback_to_savepoint(name) end
sanitize_limit(limit) 链接
清理给定的 LIMIT 参数,以防止 SQL 注入。
limit
可以是任何可以通过 to_s 评估为字符串的值。它应该看起来像一个整数,或者一个 Arel
SQL 字面量。
返回 Integer
和 Arel::Nodes::SqlLiteral limits 原样。
来源:显示 | 在 GitHub 上
# File activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb, line 508 def sanitize_limit(limit) if limit.is_a?(Integer) || limit.is_a?(Arel::Nodes::SqlLiteral) limit else Integer(limit) end 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 69 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 84 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 101 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 89 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 95 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
,则块将被包装在一个充当子事务的数据库保存点中。
为了获得嵌套事务的 ROLLBACK,您可以通过传递 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 352 def transaction(requires_new: nil, isolation: nil, joinable: true, &block) if !requires_new && current_transaction.joinable? if 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 420 def transaction_isolation_levels { read_uncommitted: "READ UNCOMMITTED", read_committed: "READ COMMITTED", repeatable_read: "REPEATABLE READ", serializable: "SERIALIZABLE" } end
transaction_open?() 链接
来源:显示 | 在 GitHub 上
# File activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb, line 379 def transaction_open? current_transaction.open? end
truncate(table_name, name = nil) 链接
执行截断语句。
来源: 显示 | 在 GitHub 上
# File activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb, line 218 def truncate(table_name, name = nil) execute(build_truncate_statement(table_name), name) end
update(arel, name = nil, binds = []) 链接
执行更新语句并返回受影响的行数。
来源: 显示 | 在 GitHub 上
# File activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb, line 206 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 118 def write_query?(sql) raise NotImplementedError end