Skip to content

Commit

Permalink
Fixed that nested transactions now work by letting the outer most tra…
Browse files Browse the repository at this point in the history
…nsaction have the responsibilty of starting and rolling back the transaction. If any of the inner transactions swallow the exception raised, though, the transaction will not be rolled back. So always let the transaction bubble up even when you've dealt with local issues. Closes #231 and #340.

git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@242 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
  • Loading branch information
dhh committed Dec 22, 2004
1 parent 58f2bd0 commit 44819b4
Show file tree
Hide file tree
Showing 4 changed files with 20 additions and 18 deletions.
4 changes: 4 additions & 0 deletions activerecord/CHANGELOG
@@ -1,5 +1,9 @@
*SVN* *SVN*


* Fixed that nested transactions now work by letting the outer most transaction have the responsibilty of starting and rolling back the transaction.
If any of the inner transactions swallow the exception raised, though, the transaction will not be rolled back. So always let the transaction
bubble up even when you've dealt with local issues. Closes #231 and #340.

* Fixed validates_{confirmation,acceptance}_of to only happen when the virtual attributes are not nil #348 [dpiddy@gmail.com] * Fixed validates_{confirmation,acceptance}_of to only happen when the virtual attributes are not nil #348 [dpiddy@gmail.com]


* Added a require_association hook on const_missing that makes it possible to use any model class without requiring it first. This makes STI look like: * Added a require_association hook on const_missing that makes it possible to use any model class without requiring it first. This makes STI look like:
Expand Down
Expand Up @@ -298,16 +298,16 @@ def reset_runtime # :nodoc:
end end


# Wrap a block in a transaction. Returns result of block. # Wrap a block in a transaction. Returns result of block.
def transaction def transaction(start_db_transaction = true)
begin begin
if block_given? if block_given?
begin_db_transaction begin_db_transaction if start_db_transaction
result = yield result = yield
commit_db_transaction commit_db_transaction if start_db_transaction
result result
end end
rescue Exception => database_transaction_rollback rescue Exception => database_transaction_rollback
rollback_db_transaction rollback_db_transaction if start_db_transaction
raise raise
end end
end end
Expand Down
24 changes: 11 additions & 13 deletions activerecord/lib/active_record/transactions.rb
Expand Up @@ -77,21 +77,27 @@ def self.append_features(base)
# Tribute: Object-level transactions are implemented by Transaction::Simple by Austin Ziegler. # Tribute: Object-level transactions are implemented by Transaction::Simple by Austin Ziegler.
module ClassMethods module ClassMethods
def transaction(*objects, &block) def transaction(*objects, &block)
TRANSACTION_MUTEX.lock TRANSACTION_MUTEX.synchronize do
Thread.current['open_transactions'] ||= 0
Thread.current['start_db_transaction'] = (Thread.current['open_transactions'] == 0)
Thread.current['open_transactions'] += 1
end


begin begin
objects.each { |o| o.extend(Transaction::Simple) } objects.each { |o| o.extend(Transaction::Simple) }
objects.each { |o| o.start_transaction } objects.each { |o| o.start_transaction }


result = connection.transaction(&block) result = connection.transaction(Thread.current['start_db_transaction'], &block)


objects.each { |o| o.commit_transaction } objects.each { |o| o.commit_transaction }
return result return result
rescue Exception => object_transaction_rollback rescue Exception => object_transaction_rollback
objects.each { |o| o.abort_transaction } objects.each { |o| o.abort_transaction }
raise raise
ensure ensure
TRANSACTION_MUTEX.unlock TRANSACTION_MUTEX.synchronize do
Thread.current['open_transactions'] -= 1
end
end end
end end
end end
Expand All @@ -101,19 +107,11 @@ def transaction(*objects, &block)
end end


def destroy_with_transactions #:nodoc: def destroy_with_transactions #:nodoc:
if TRANSACTION_MUTEX.locked? transaction { destroy_without_transactions }
destroy_without_transactions
else
transaction { destroy_without_transactions }
end
end end


def save_with_transactions(perform_validation = true) #:nodoc: def save_with_transactions(perform_validation = true) #:nodoc:
if TRANSACTION_MUTEX.locked? transaction { save_without_transactions(perform_validation) }
save_without_transactions(perform_validation)
else
transaction { save_without_transactions(perform_validation) }
end
end end
end end
end end
2 changes: 1 addition & 1 deletion activerecord/test/transactions_test.rb
Expand Up @@ -84,7 +84,7 @@ def test_callback_rollback_in_save
end end
end end


def xtest_nested_explicit_transactions def test_nested_explicit_transactions
Topic.transaction do Topic.transaction do
Topic.transaction do Topic.transaction do
@first.approved = 1 @first.approved = 1
Expand Down

0 comments on commit 44819b4

Please sign in to comment.