diff options
Diffstat (limited to 'activerecord/lib/active_record/connection_adapters/abstract/transaction.rb')
-rw-r--r-- | activerecord/lib/active_record/connection_adapters/abstract/transaction.rb | 189 |
1 files changed, 75 insertions, 114 deletions
diff --git a/activerecord/lib/active_record/connection_adapters/abstract/transaction.rb b/activerecord/lib/active_record/connection_adapters/abstract/transaction.rb index 33cc22425d..46aaaae2ec 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/transaction.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/transaction.rb @@ -1,76 +1,5 @@ module ActiveRecord module ConnectionAdapters - class TransactionManager #:nodoc: - def initialize(connection) - @stack = [] - @connection = connection - end - - def begin_transaction(options = {}) - transaction_class = @stack.empty? ? RealTransaction : SavepointTransaction - transaction = transaction_class.new(@connection, current_transaction, options) - - @stack.push(transaction) - transaction - end - - def commit_transaction - @stack.pop.commit - end - - def rollback_transaction - @stack.pop.rollback - end - - def within_new_transaction(options = {}) - transaction = begin_transaction options - yield - rescue Exception => error - transaction.rollback if transaction - raise - ensure - begin - transaction.commit unless error - rescue Exception - transaction.rollback - raise - ensure - @stack.pop if transaction - end - end - - def open_transactions - @stack.size - end - - def current_transaction - @stack.last || closed_transaction - end - - private - - def closed_transaction - @closed_transaction ||= ClosedTransaction.new(@connection) - end - end - - class Transaction #:nodoc: - attr_reader :connection - - def initialize(connection) - @connection = connection - @state = TransactionState.new - end - - def state - @state - end - - def savepoint_name - nil - end - end - class TransactionState attr_reader :parent @@ -101,65 +30,49 @@ module ActiveRecord end end - class ClosedTransaction < Transaction #:nodoc: - def number - 0 - end - - def begin(options = {}) - RealTransaction.new(connection, self, options) - end - - def closed? - true - end + class Transaction #:nodoc: + attr_reader :connection, :state - def open? - false + def initialize(connection) + @connection = connection + @state = TransactionState.new end - def joinable? - false + def savepoint_name + nil end + end + class NullTransaction < Transaction #: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 + def add_record(record); end end class OpenTransaction < Transaction #:nodoc: - attr_reader :parent, :records + attr_reader :records attr_writer :joinable - def initialize(connection, parent, options = {}) + def initialize(connection, options = {}) super connection - @parent = parent @records = [] @joinable = options.fetch(:joinable, true) end - def joinable? @joinable end - def number - parent.number + 1 - end - - def begin(options = {}) - SavepointTransaction.new(connection, self, options) - end - def rollback perform_rollback - parent end def commit perform_commit - parent end def add_record(record) @@ -174,7 +87,7 @@ module ActiveRecord @state.set_state(:rolledback) records.uniq.each do |record| begin - record.rolledback!(parent.closed?) + record.rolledback!(self.is_a?(RealTransaction)) rescue => e record.logger.error(e) if record.respond_to?(:logger) && record.logger end @@ -202,8 +115,8 @@ module ActiveRecord end class RealTransaction < OpenTransaction #:nodoc: - def initialize(connection, parent, options = {}) - super + def initialize(connection, _, options = {}) + super(connection, options) if options[:isolation] connection.begin_isolated_db_transaction(options[:isolation]) @@ -226,27 +139,75 @@ module ActiveRecord class SavepointTransaction < OpenTransaction #:nodoc: attr_reader :savepoint_name - def initialize(connection, parent, options = {}) + def initialize(connection, savepoint_name, options = {}) if options[:isolation] raise ActiveRecord::TransactionIsolationError, "cannot set transaction isolation in a nested transaction" end - super - - # Savepoint name only counts the Savepoint transactions, so we need to subtract 1 - @savepoint_name = "active_record_#{number - 1}" - connection.create_savepoint(@savepoint_name) + super(connection, options) + connection.create_savepoint(@savepoint_name = savepoint_name) end def perform_rollback - connection.rollback_to_savepoint(@savepoint_name) + connection.rollback_to_savepoint(savepoint_name) rollback_records end def perform_commit @state.set_state(:committed) - connection.release_savepoint(@savepoint_name) + connection.release_savepoint(savepoint_name) + end + end + + class TransactionManager #:nodoc: + def initialize(connection) + @stack = [] + @connection = connection + end + + def begin_transaction(options = {}) + transaction_class = @stack.empty? ? RealTransaction : SavepointTransaction + transaction = transaction_class.new(@connection, "active_record_#{@stack.size}", options) + + @stack.push(transaction) + transaction end + + def commit_transaction + @stack.pop.commit + end + + def rollback_transaction + @stack.pop.rollback + end + + def within_new_transaction(options = {}) + transaction = begin_transaction options + yield + rescue Exception => error + transaction.rollback if transaction + raise + ensure + begin + transaction.commit unless error + rescue Exception + transaction.rollback + raise + ensure + @stack.pop if transaction + end + end + + def open_transactions + @stack.size + end + + def current_transaction + @stack.last || NULL_TRANSACTION + end + + private + NULL_TRANSACTION = NullTransaction.new end end end |