Class: ActiveRecord::ConnectionAdapters::TransactionManager

Inherits:
Object
  • Object
show all
Defined in:
lib/active_record/connection_adapters/abstract/transaction.rb

Overview

:nodoc:

Instance Method Summary collapse

Constructor Details

#initialize(connection) ⇒ TransactionManager

Returns a new instance of TransactionManager.



225
226
227
228
229
230
231
# File 'lib/active_record/connection_adapters/abstract/transaction.rb', line 225

def initialize(connection)
  @stack = []
  @connection = connection
  @has_unmaterialized_transactions = false
  @materializing_transactions = false
  @lazy_transactions_enabled = true
end

Instance Method Details

#begin_transaction(isolation: nil, joinable: true, _lazy: true) ⇒ Object



233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
# File 'lib/active_record/connection_adapters/abstract/transaction.rb', line 233

def begin_transaction(isolation: nil, joinable: true, _lazy: true)
  @connection.lock.synchronize do
    run_commit_callbacks = !current_transaction.joinable?
    transaction =
      if @stack.empty?
        RealTransaction.new(
          @connection,
          isolation: isolation,
          joinable: joinable,
          run_commit_callbacks: run_commit_callbacks
        )
      else
        SavepointTransaction.new(
          @connection,
          "active_record_#{@stack.size}",
          @stack.last,
          isolation: isolation,
          joinable: joinable,
          run_commit_callbacks: run_commit_callbacks
        )
      end

    if @connection.supports_lazy_transactions? && lazy_transactions_enabled? && _lazy
      @has_unmaterialized_transactions = true
    else
      transaction.materialize!
    end
    @stack.push(transaction)
    transaction
  end
end

#commit_transactionObject



293
294
295
296
297
298
299
300
301
302
303
304
305
306
# File 'lib/active_record/connection_adapters/abstract/transaction.rb', line 293

def commit_transaction
  @connection.lock.synchronize do
    transaction = @stack.last

    begin
      transaction.before_commit_records
    ensure
      @stack.pop
    end

    transaction.commit
    transaction.commit_records
  end
end

#current_transactionObject



366
367
368
# File 'lib/active_record/connection_adapters/abstract/transaction.rb', line 366

def current_transaction
  @stack.last || NULL_TRANSACTION
end

#disable_lazy_transactions!Object



265
266
267
268
# File 'lib/active_record/connection_adapters/abstract/transaction.rb', line 265

def disable_lazy_transactions!
  materialize_transactions
  @lazy_transactions_enabled = false
end

#enable_lazy_transactions!Object



270
271
272
# File 'lib/active_record/connection_adapters/abstract/transaction.rb', line 270

def enable_lazy_transactions!
  @lazy_transactions_enabled = true
end

#lazy_transactions_enabled?Boolean

Returns:

  • (Boolean)


274
275
276
# File 'lib/active_record/connection_adapters/abstract/transaction.rb', line 274

def lazy_transactions_enabled?
  @lazy_transactions_enabled
end

#materialize_transactionsObject



278
279
280
281
282
283
284
285
286
287
288
289
290
291
# File 'lib/active_record/connection_adapters/abstract/transaction.rb', line 278

def materialize_transactions
  return if @materializing_transactions
  return unless @has_unmaterialized_transactions

  @connection.lock.synchronize do
    begin
      @materializing_transactions = true
      @stack.each { |t| t.materialize! unless t.materialized? }
    ensure
      @materializing_transactions = false
    end
    @has_unmaterialized_transactions = false
  end
end

#open_transactionsObject



362
363
364
# File 'lib/active_record/connection_adapters/abstract/transaction.rb', line 362

def open_transactions
  @stack.size
end

#rollback_transaction(transaction = nil) ⇒ Object



308
309
310
311
312
313
314
# File 'lib/active_record/connection_adapters/abstract/transaction.rb', line 308

def rollback_transaction(transaction = nil)
  @connection.lock.synchronize do
    transaction ||= @stack.pop
    transaction.rollback unless transaction.state.invalidated?
    transaction.rollback_records
  end
end

#within_new_transaction(isolation: nil, joinable: true) ⇒ Object



316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
# File 'lib/active_record/connection_adapters/abstract/transaction.rb', line 316

def within_new_transaction(isolation: nil, joinable: true)
  @connection.lock.synchronize do
    transaction = begin_transaction(isolation: isolation, joinable: joinable)
    ret = yield
    completed = true
    ret
  rescue Exception => error
    if transaction
      transaction.state.invalidate! if error.is_a? ActiveRecord::TransactionRollbackError
      rollback_transaction
      after_failure_actions(transaction, error)
    end

    raise
  ensure
    if transaction
      if error
        # @connection still holds an open or invalid transaction, so we must not
        # put it back in the pool for reuse.
        @connection.throw_away! unless transaction.state.rolledback?
      else
        if Thread.current.status == "aborting"
          rollback_transaction
        else
          if !completed && transaction.written
            ActiveSupport::Deprecation.warn(<<~EOW)
              Using `return`, `break` or `throw` to exit a transaction block is
              deprecated without replacement. If the `throw` came from
              `Timeout.timeout(duration)`, pass an exception class as a second
              argument so it doesn't use `throw` to abort its block. This results
              in the transaction being committed, but in the next release of Rails
              it will rollback.
            EOW
          end
          begin
            commit_transaction
          rescue Exception
            rollback_transaction(transaction) unless transaction.state.completed?
            raise
          end
        end
      end
    end
  end
end