aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord
diff options
context:
space:
mode:
authorHongli Lai (Phusion) <hongli@phusion.nl>2008-10-09 16:24:15 +0200
committerHongli Lai (Phusion) <hongli@phusion.nl>2008-11-03 20:56:21 +0100
commite916aa7ea1613be966959c05ad41d13fee55a683 (patch)
treeaf4c0af070225f2e6b2d0eccc62b48021634a225 /activerecord
parent885c11b8f9e18f34b12076023455e72166365f00 (diff)
downloadrails-e916aa7ea1613be966959c05ad41d13fee55a683.tar.gz
rails-e916aa7ea1613be966959c05ad41d13fee55a683.tar.bz2
rails-e916aa7ea1613be966959c05ad41d13fee55a683.zip
Rename ActiveRecord::Base#transaction's :force option to :nest. Improve documentation for nested transactions.
Diffstat (limited to 'activerecord')
-rw-r--r--activerecord/lib/active_record/transactions.rb59
-rw-r--r--activerecord/test/cases/transactions_test.rb10
2 files changed, 62 insertions, 7 deletions
diff --git a/activerecord/lib/active_record/transactions.rb b/activerecord/lib/active_record/transactions.rb
index 4bac7b39d9..1e0185d39c 100644
--- a/activerecord/lib/active_record/transactions.rb
+++ b/activerecord/lib/active_record/transactions.rb
@@ -120,14 +120,69 @@ module ActiveRecord
# 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
diff --git a/activerecord/test/cases/transactions_test.rb b/activerecord/test/cases/transactions_test.rb
index 3c6bfd7e22..069ba9d6c5 100644
--- a/activerecord/test/cases/transactions_test.rb
+++ b/activerecord/test/cases/transactions_test.rb
@@ -215,7 +215,7 @@ class TransactionTest < ActiveRecord::TestCase
def test_invalid_keys_for_transaction
assert_raises ArgumentError do
- Topic.transaction :forced => true do
+ Topic.transaction :nested => true do
end
end
end
@@ -228,7 +228,7 @@ class TransactionTest < ActiveRecord::TestCase
@second.save!
begin
- Topic.transaction :force => true do
+ Topic.transaction :nest => true do
@first.happy = false
@first.save!
raise
@@ -268,17 +268,17 @@ class TransactionTest < ActiveRecord::TestCase
@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