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.
git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@242 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
This commit is contained in:
parent
58f2bd0cfc
commit
44819b4717
@ -1,5 +1,9 @@
|
||||
*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]
|
||||
|
||||
* 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:
|
||||
|
@ -298,16 +298,16 @@ def reset_runtime # :nodoc:
|
||||
end
|
||||
|
||||
# Wrap a block in a transaction. Returns result of block.
|
||||
def transaction
|
||||
def transaction(start_db_transaction = true)
|
||||
begin
|
||||
if block_given?
|
||||
begin_db_transaction
|
||||
begin_db_transaction if start_db_transaction
|
||||
result = yield
|
||||
commit_db_transaction
|
||||
commit_db_transaction if start_db_transaction
|
||||
result
|
||||
end
|
||||
rescue Exception => database_transaction_rollback
|
||||
rollback_db_transaction
|
||||
rollback_db_transaction if start_db_transaction
|
||||
raise
|
||||
end
|
||||
end
|
||||
|
@ -77,13 +77,17 @@ def self.append_features(base)
|
||||
# Tribute: Object-level transactions are implemented by Transaction::Simple by Austin Ziegler.
|
||||
module ClassMethods
|
||||
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
|
||||
objects.each { |o| o.extend(Transaction::Simple) }
|
||||
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 }
|
||||
return result
|
||||
@ -91,7 +95,9 @@ def transaction(*objects, &block)
|
||||
objects.each { |o| o.abort_transaction }
|
||||
raise
|
||||
ensure
|
||||
TRANSACTION_MUTEX.unlock
|
||||
TRANSACTION_MUTEX.synchronize do
|
||||
Thread.current['open_transactions'] -= 1
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -101,19 +107,11 @@ def transaction(*objects, &block)
|
||||
end
|
||||
|
||||
def destroy_with_transactions #:nodoc:
|
||||
if TRANSACTION_MUTEX.locked?
|
||||
destroy_without_transactions
|
||||
else
|
||||
transaction { destroy_without_transactions }
|
||||
end
|
||||
transaction { destroy_without_transactions }
|
||||
end
|
||||
|
||||
def save_with_transactions(perform_validation = true) #:nodoc:
|
||||
if TRANSACTION_MUTEX.locked?
|
||||
save_without_transactions(perform_validation)
|
||||
else
|
||||
transaction { save_without_transactions(perform_validation) }
|
||||
end
|
||||
transaction { save_without_transactions(perform_validation) }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -84,7 +84,7 @@ def test_callback_rollback_in_save
|
||||
end
|
||||
end
|
||||
|
||||
def xtest_nested_explicit_transactions
|
||||
def test_nested_explicit_transactions
|
||||
Topic.transaction do
|
||||
Topic.transaction do
|
||||
@first.approved = 1
|
||||
|
Loading…
Reference in New Issue
Block a user