mirror of
https://github.com/rails/rails.git
synced 2022-11-09 12:12:34 -05:00
Rename ActiveRecord::Base#transaction's :force option to :nest. Improve documentation for nested transactions.
This commit is contained in:
parent
885c11b8f9
commit
e916aa7ea1
2 changed files with 62 additions and 7 deletions
|
@ -120,14 +120,69 @@ module ActiveRecord
|
||||||
# end
|
# end
|
||||||
#
|
#
|
||||||
# One should restart the entire transaction if a StatementError occurred.
|
# One should restart the entire transaction if a StatementError occurred.
|
||||||
|
#
|
||||||
|
# == Nested transactions
|
||||||
|
#
|
||||||
|
# #transaction calls can be nested. By default, this makes all database
|
||||||
|
# statements in the nested transaction block become part of the parent
|
||||||
|
# transaction. For example:
|
||||||
|
#
|
||||||
|
# User.transaction do
|
||||||
|
# User.create(:username => 'Kotori')
|
||||||
|
# User.transaction do
|
||||||
|
# User.create(:username => 'Nemu')
|
||||||
|
# raise ActiveRecord::Rollback
|
||||||
|
# end
|
||||||
|
# end
|
||||||
|
#
|
||||||
|
# User.find(:all) # => empty
|
||||||
|
#
|
||||||
|
# It is also possible to treat a certain #transaction call as its own
|
||||||
|
# sub-transaction, by passing <tt>:nest => true</tt> to #transaction. If
|
||||||
|
# anything goes wrong inside that transaction block, then the parent
|
||||||
|
# transaction will remain unaffected. For example:
|
||||||
|
#
|
||||||
|
# User.transaction do
|
||||||
|
# User.create(:username => 'Kotori')
|
||||||
|
# User.transaction(:nest => true) do
|
||||||
|
# User.create(:username => 'Nemu')
|
||||||
|
# raise ActiveRecord::Rollback
|
||||||
|
# end
|
||||||
|
# end
|
||||||
|
#
|
||||||
|
# User.find(:all) # => Returns only Kotori
|
||||||
|
#
|
||||||
|
# Most databases don't support true nested transactions. At the time of
|
||||||
|
# writing, the only database that we're aware of that supports true nested
|
||||||
|
# transactions, is MS-SQL. Because of this, Active Record emulates nested
|
||||||
|
# transactions by using savepoints. See
|
||||||
|
# http://dev.mysql.com/doc/refman/5.0/en/savepoints.html
|
||||||
|
# for more information about savepoints.
|
||||||
|
#
|
||||||
|
# === Caveats
|
||||||
|
#
|
||||||
|
# If you're on MySQL, then do not use DDL operations in nested transactions
|
||||||
|
# blocks that are emulated with savepoints. That is, do not execute statements
|
||||||
|
# like 'CREATE TABLE' inside such blocks. This is because MySQL automatically
|
||||||
|
# releases all savepoints upon executing a DDL operation. When #transaction
|
||||||
|
# is finished and tries to release the savepoint it created earlier, a
|
||||||
|
# database error will occur because the savepoint has already been
|
||||||
|
# automatically released. The following example demonstrates the problem:
|
||||||
|
#
|
||||||
|
# Model.connection.transaction do # BEGIN
|
||||||
|
# Model.connection.transaction(true) do # CREATE SAVEPOINT rails_savepoint_1
|
||||||
|
# Model.connection.create_table(...) # rails_savepoint_1 now automatically released
|
||||||
|
# end # RELEASE savepoint rails_savepoint_1
|
||||||
|
# # ^^^^ BOOM! database error!
|
||||||
|
# end
|
||||||
module ClassMethods
|
module ClassMethods
|
||||||
# See ActiveRecord::Transactions::ClassMethods for detailed documentation.
|
# See ActiveRecord::Transactions::ClassMethods for detailed documentation.
|
||||||
def transaction(options = {}, &block)
|
def transaction(options = {}, &block)
|
||||||
options.assert_valid_keys :force
|
options.assert_valid_keys :nest
|
||||||
|
|
||||||
# See the API documentation for ConnectionAdapters::DatabaseStatements#transaction
|
# See the API documentation for ConnectionAdapters::DatabaseStatements#transaction
|
||||||
# for useful information.
|
# for useful information.
|
||||||
connection.transaction(options[:force], &block)
|
connection.transaction(options[:nest], &block)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -215,7 +215,7 @@ class TransactionTest < ActiveRecord::TestCase
|
||||||
|
|
||||||
def test_invalid_keys_for_transaction
|
def test_invalid_keys_for_transaction
|
||||||
assert_raises ArgumentError do
|
assert_raises ArgumentError do
|
||||||
Topic.transaction :forced => true do
|
Topic.transaction :nested => true do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -228,7 +228,7 @@ class TransactionTest < ActiveRecord::TestCase
|
||||||
@second.save!
|
@second.save!
|
||||||
|
|
||||||
begin
|
begin
|
||||||
Topic.transaction :force => true do
|
Topic.transaction :nest => true do
|
||||||
@first.happy = false
|
@first.happy = false
|
||||||
@first.save!
|
@first.save!
|
||||||
raise
|
raise
|
||||||
|
@ -268,17 +268,17 @@ class TransactionTest < ActiveRecord::TestCase
|
||||||
@first.save!
|
@first.save!
|
||||||
|
|
||||||
begin
|
begin
|
||||||
Topic.transaction :force => true do
|
Topic.transaction :nest => true do
|
||||||
@first.content = "Two"
|
@first.content = "Two"
|
||||||
@first.save!
|
@first.save!
|
||||||
|
|
||||||
begin
|
begin
|
||||||
Topic.transaction :force => true do
|
Topic.transaction :nest => true do
|
||||||
@first.content = "Three"
|
@first.content = "Three"
|
||||||
@first.save!
|
@first.save!
|
||||||
|
|
||||||
begin
|
begin
|
||||||
Topic.transaction :force => true do
|
Topic.transaction :nest => true do
|
||||||
@first.content = "Four"
|
@first.content = "Four"
|
||||||
@first.save!
|
@first.save!
|
||||||
raise
|
raise
|
||||||
|
|
Loading…
Reference in a new issue