Skip to content

Commit

Permalink
Rename ActiveRecord::Base#transaction's :force option to :nest. Impro…
Browse files Browse the repository at this point in the history
…ve documentation for nested transactions.
  • Loading branch information
FooBarWidget committed Nov 3, 2008
1 parent 885c11b commit e916aa7
Show file tree
Hide file tree
Showing 2 changed files with 62 additions and 7 deletions.
59 changes: 57 additions & 2 deletions activerecord/lib/active_record/transactions.rb
Expand Up @@ -120,14 +120,69 @@ def self.included(base)
# end
#
# 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
# See ActiveRecord::Transactions::ClassMethods for detailed documentation.
def transaction(options = {}, &block)
options.assert_valid_keys :force
options.assert_valid_keys :nest

# See the API documentation for ConnectionAdapters::DatabaseStatements#transaction
# for useful information.
connection.transaction(options[:force], &block)
connection.transaction(options[:nest], &block)
end
end

Expand Down
10 changes: 5 additions & 5 deletions activerecord/test/cases/transactions_test.rb
Expand Up @@ -215,7 +215,7 @@ def test_manually_rolling_back_a_transaction

def test_invalid_keys_for_transaction
assert_raises ArgumentError do
Topic.transaction :forced => true do
Topic.transaction :nested => true do
end
end
end
Expand All @@ -228,7 +228,7 @@ def test_force_savepoint_in_nested_transaction
@second.save!

begin
Topic.transaction :force => true do
Topic.transaction :nest => true do
@first.happy = false
@first.save!
raise
Expand Down Expand Up @@ -268,17 +268,17 @@ def test_many_savepoints
@first.save!

begin
Topic.transaction :force => true do
Topic.transaction :nest => true do
@first.content = "Two"
@first.save!

begin
Topic.transaction :force => true do
Topic.transaction :nest => true do
@first.content = "Three"
@first.save!

begin
Topic.transaction :force => true do
Topic.transaction :nest => true do
@first.content = "Four"
@first.save!
raise
Expand Down

0 comments on commit e916aa7

Please sign in to comment.