Cleanup Transaction inheritance.

Transaction class doesnt need to encapsulate the transaction state using
inheritance.
This removes all Transaction subclasses, and let the Transaction object
controls different actions based on its own state. Basically the only
actions would behave differently are `being`,`commit`,`rollback` as they
could act in a savepoint or in a real transaction.
This commit is contained in:
Arthur Neves 2014-07-31 16:44:55 -04:00
parent c8317cd1d4
commit 8298d3adb7
No known key found for this signature in database
GPG Key ID: 04A390FB1E433E17
2 changed files with 61 additions and 77 deletions

View File

@ -30,49 +30,24 @@ module ActiveRecord
end
end
class Transaction #:nodoc:
attr_reader :connection, :state
def initialize(connection)
@connection = connection
@state = TransactionState.new
end
def savepoint_name
nil
end
end
class NullTransaction < Transaction #:nodoc:
class NullTransaction #:nodoc:
def initialize; end
def closed?; true; end
def open?; false; end
def joinable?; false; end
# This is a noop when there are no open transactions
def add_record(record); end
end
class OpenTransaction < Transaction #:nodoc:
attr_reader :records
class Transaction #:nodoc:
attr_reader :connection, :state, :records, :savepoint_name
attr_writer :joinable
def initialize(connection, options = {})
super connection
@records = []
@joinable = options.fetch(:joinable, true)
end
def joinable?
@joinable
end
def rollback
perform_rollback
end
def commit
perform_commit
def initialize(connection, options)
@connection = connection
@state = TransactionState.new
@records = []
@joinable = options.fetch(:joinable, true)
end
def add_record(record)
@ -83,19 +58,25 @@ module ActiveRecord
end
end
def rollback_records
def rollback
@state.set_state(:rolledback)
end
def rollback_records
records.uniq.each do |record|
begin
record.rolledback!(self.is_a?(RealTransaction))
record.rolledback! full_rollback?
rescue => e
record.logger.error(e) if record.respond_to?(:logger) && record.logger
end
end
end
def commit_records
def commit
@state.set_state(:committed)
end
def commit_records
records.uniq.each do |record|
begin
record.committed!
@ -105,19 +86,40 @@ module ActiveRecord
end
end
def closed?
false
end
def open?
true
end
def full_rollback?; true; end
def joinable?; @joinable; end
def closed?; false; end
def open?; !closed?; end
end
class RealTransaction < OpenTransaction #:nodoc:
def initialize(connection, _, options = {})
super(connection, options)
class SavepointTransaction < Transaction
def initialize(connection, savepoint_name, options)
super(connection, options)
if options[:isolation]
raise ActiveRecord::TransactionIsolationError, "cannot set transaction isolation in a nested transaction"
end
connection.create_savepoint(@savepoint_name = savepoint_name)
end
def rollback
super
connection.rollback_to_savepoint(savepoint_name)
rollback_records
end
def commit
super
connection.release_savepoint(savepoint_name)
end
def full_rollback?; false; end
end
class RealTransaction < Transaction
def initialize(connection, options)
super
if options[:isolation]
connection.begin_isolated_db_transaction(options[:isolation])
else
@ -125,40 +127,19 @@ module ActiveRecord
end
end
def perform_rollback
def rollback
super
connection.rollback_db_transaction
rollback_records
end
def perform_commit
def commit
super
connection.commit_db_transaction
commit_records
end
end
class SavepointTransaction < OpenTransaction #:nodoc:
attr_reader :savepoint_name
def initialize(connection, savepoint_name, options = {})
if options[:isolation]
raise ActiveRecord::TransactionIsolationError, "cannot set transaction isolation in a nested transaction"
end
super(connection, options)
connection.create_savepoint(@savepoint_name = savepoint_name)
end
def perform_rollback
connection.rollback_to_savepoint(savepoint_name)
rollback_records
end
def perform_commit
@state.set_state(:committed)
connection.release_savepoint(savepoint_name)
end
end
class TransactionManager #:nodoc:
def initialize(connection)
@stack = []
@ -166,9 +147,12 @@ module ActiveRecord
end
def begin_transaction(options = {})
transaction_class = @stack.empty? ? RealTransaction : SavepointTransaction
transaction = transaction_class.new(@connection, "active_record_#{@stack.size}", options)
transaction =
if @stack.empty?
RealTransaction.new(@connection, options)
else
SavepointTransaction.new(@connection, "active_record_#{@stack.size}", options)
end
@stack.push(transaction)
transaction
end

View File

@ -552,7 +552,7 @@ class TransactionTest < ActiveRecord::TestCase
assert !transaction.state.rolledback?
assert !transaction.state.committed?
transaction.perform_rollback
transaction.rollback
assert transaction.state.rolledback?
assert !transaction.state.committed?
@ -566,7 +566,7 @@ class TransactionTest < ActiveRecord::TestCase
assert !transaction.state.rolledback?
assert !transaction.state.committed?
transaction.perform_commit
transaction.commit
assert !transaction.state.rolledback?
assert transaction.state.committed?