diff options
Diffstat (limited to 'activerecord/lib/active_record/transactions.rb')
-rw-r--r-- | activerecord/lib/active_record/transactions.rb | 40 |
1 files changed, 21 insertions, 19 deletions
diff --git a/activerecord/lib/active_record/transactions.rb b/activerecord/lib/active_record/transactions.rb index ab737f0f88..48d2f7c9a9 100644 --- a/activerecord/lib/active_record/transactions.rb +++ b/activerecord/lib/active_record/transactions.rb @@ -11,6 +11,7 @@ module ActiveRecord included do define_callbacks :commit, :rollback, :terminator => "result == false", :scope => [:kind, :name] end + # = Active Record Transactions # # Transactions are protective blocks where SQL statements are only permanent @@ -130,7 +131,7 @@ module ActiveRecord # # +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: + # transaction. For example, the following behavior may be surprising: # # User.transaction do # User.create(:username => 'Kotori') @@ -140,12 +141,15 @@ module ActiveRecord # end # end # - # User.find(:all) # => empty + # creates both "Kotori" and "Nemu". Reason is the <tt>ActiveRecord::Rollback</tt> + # exception in the nested block does not issue a ROLLBACK. Since these exceptions + # are captured in transaction blocks, the parent block does not see it and the + # real transaction is committed. # - # It is also possible to requires a sub-transaction by passing - # <tt>:requires_new => true</tt>. If anything goes wrong, the - # database rolls back to the beginning of the sub-transaction - # without rolling back the parent transaction. For example: + # In order to get a ROLLBACK for the nested transaction you may ask for a real + # sub-transaction by passing <tt>:requires_new => true</tt>. If anything goes wrong, + # the database rolls back to the beginning of the sub-transaction without rolling + # back the parent transaction. If we add it to the previous example: # # User.transaction do # User.create(:username => 'Kotori') @@ -155,12 +159,12 @@ module ActiveRecord # end # end # - # User.find(:all) # => Returns only Kotori + # only "Kotori" is created. (This works on MySQL and PostgreSQL, but not on SQLite3.) # # 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 + # transactions by using savepoints on MySQL and PostgreSQL. See # http://dev.mysql.com/doc/refman/5.0/en/savepoints.html # for more information about savepoints. # @@ -297,8 +301,8 @@ module ActiveRecord # Save the new record state and id of a record so it can be restored later if a transaction fails. def remember_transaction_record_state #:nodoc @_start_transaction_state ||= {} + @_start_transaction_state[:id] = id if has_attribute?(self.class.primary_key) unless @_start_transaction_state.include?(:new_record) - @_start_transaction_state[:id] = id if has_attribute?(self.class.primary_key) @_start_transaction_state[:new_record] = @new_record end unless @_start_transaction_state.include?(:destroyed) @@ -321,16 +325,14 @@ module ActiveRecord @_start_transaction_state[:level] = (@_start_transaction_state[:level] || 0) - 1 if @_start_transaction_state[:level] < 1 restore_state = remove_instance_variable(:@_start_transaction_state) - if restore_state - @attributes = @attributes.dup if @attributes.frozen? - @new_record = restore_state[:new_record] - @destroyed = restore_state[:destroyed] - if restore_state[:id] - self.id = restore_state[:id] - else - @attributes.delete(self.class.primary_key) - @attributes_cache.delete(self.class.primary_key) - end + @attributes = @attributes.dup if @attributes.frozen? + @new_record = restore_state[:new_record] + @destroyed = restore_state[:destroyed] + if restore_state.has_key?(:id) + self.id = restore_state[:id] + else + @attributes.delete(self.class.primary_key) + @attributes_cache.delete(self.class.primary_key) end end end |