Module: TransactionIsolation::ActiveRecord::ConnectionAdapters::Mysql2Adapter

Defined in:
lib/transaction_isolation/active_record/connection_adapters/mysql2_adapter.rb

Constant Summary collapse

VENDOR_ISOLATION_LEVEL =
{
  read_uncommitted: 'READ UNCOMMITTED',
  read_committed: 'READ COMMITTED',
  repeatable_read: 'REPEATABLE READ',
  serializable: 'SERIALIZABLE'
}.freeze
ANSI_ISOLATION_LEVEL =
{
  'READ UNCOMMITTED' => :read_uncommitted,
  'READ COMMITTED' => :read_committed,
  'REPEATABLE READ' => :repeatable_read,
  'SERIALIZABLE' => :serializable
}.freeze

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.included(base) ⇒ Object



9
10
11
12
13
14
# File 'lib/transaction_isolation/active_record/connection_adapters/mysql2_adapter.rb', line 9

def self.included(base)
  base.class_eval do
    alias_method :translate_exception_without_transaction_isolation_conflict, :translate_exception
    alias_method :translate_exception, :translate_exception_with_transaction_isolation_conflict
  end
end

Instance Method Details

#current_isolation_levelObject



34
35
36
# File 'lib/transaction_isolation/active_record/connection_adapters/mysql2_adapter.rb', line 34

def current_isolation_level
  ANSI_ISOLATION_LEVEL[current_vendor_isolation_level]
end

#current_vendor_isolation_levelObject

transaction_isolation was added in MySQL 5.7.20 as an alias for tx_isolation, which is now deprecated and is removed in MySQL 8.0. Applications should be adjusted to use transaction_isolation in preference to tx_isolation.



39
40
41
42
# File 'lib/transaction_isolation/active_record/connection_adapters/mysql2_adapter.rb', line 39

def current_vendor_isolation_level
  isolation_variable = TransactionIsolation.config.mysql_isolation_variable
  select_value("SELECT @@session.#{isolation_variable}").gsub('-', ' ')
end

#isolation_conflict?(exception) ⇒ Boolean

Returns:

  • (Boolean)


72
73
74
75
76
77
# File 'lib/transaction_isolation/active_record/connection_adapters/mysql2_adapter.rb', line 72

def isolation_conflict?(exception)
  ['Deadlock found when trying to get lock',
   'Lock wait timeout exceeded'].any? do |error_message|
    exception.message =~ /#{Regexp.escape(error_message)}/i
  end
end

#isolation_level(level) ⇒ Object



44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
# File 'lib/transaction_isolation/active_record/connection_adapters/mysql2_adapter.rb', line 44

def isolation_level(level)
  validate_isolation_level(level)

  original_vendor_isolation_level = current_vendor_isolation_level if block_given?

  execute("SET SESSION TRANSACTION ISOLATION LEVEL #{VENDOR_ISOLATION_LEVEL[level]}")

  return unless block_given?

  begin
    yield
  ensure
    execute "SET SESSION TRANSACTION ISOLATION LEVEL #{original_vendor_isolation_level}"
  end
end

#supports_isolation_levels?Boolean

Returns:

  • (Boolean)


16
17
18
# File 'lib/transaction_isolation/active_record/connection_adapters/mysql2_adapter.rb', line 16

def supports_isolation_levels?
  true
end

#translate_exception_with_transaction_isolation_conflict(*args) ⇒ Object



60
61
62
63
64
65
66
67
68
# File 'lib/transaction_isolation/active_record/connection_adapters/mysql2_adapter.rb', line 60

def translate_exception_with_transaction_isolation_conflict(*args)
  exception = args.first

  if isolation_conflict?(exception)
    ::ActiveRecord::TransactionIsolationConflict.new("Transaction isolation conflict detected: #{exception.message}")
  else
    translate_exception_without_transaction_isolation_conflict(*args)
  end
end