Skip to content

Instantly share code, notes, and snippets.

@HugoLnx
Created June 14, 2014 16:45
Show Gist options
  • Save HugoLnx/5a66b21161c9812c2101 to your computer and use it in GitHub Desktop.
Save HugoLnx/5a66b21161c9812c2101 to your computer and use it in GitHub Desktop.
require 'mysql2'
def open_connection
Mysql2::Client.new(host: 'localhost', username: 'root', database: 'repeatable_read_test')
end
class ThreadLogger
def initialize(id)
@id = id
end
def log(msg)
puts "Thread #{@id}: #{msg}"
end
end
class Mysql2Error
DEADLOCK_ERROR_NUMBER = 1213
def initialize(error)
@error = error
end
def deadlock?
@error.error_number == DEADLOCK_ERROR_NUMBER
end
end
# DAO comum de pessoa
class PessoaDAO
def initialize(con)
@db = con
end
def insert(new_name, new_age, new_email)
@db.query("insert into Pessoa values('#{new_name}', #{new_age}, '#{new_email}', NOW() + INTERVAL 1 DAY)")
end
def exist_people_created_a_minute_ago_with_name(name)
results = @db.query("select * from Pessoa p where p.nome = #{name.inspect} AND p.created_at >= NOW() + INTERVAL 1 MINUTE")
results.to_a.size != 0
end
end
# DAO especial que abre transação própria verificar se a inserção pode ocorrer e executa a inserção se necessário
class PessoaNonRecentRepeatedInsertionDAO
def initialize(con, dao, l)
@db = con
@dao = dao
@l = l
end
def insert(new_name, new_age, new_email)
begin
@db.query("set session transaction isolation level serializable")
@db.query("start transaction")
if @dao.exist_people_created_a_minute_ago_with_name(new_name)
@l.log "Já foi inserida recentemente"
else
@dao.insert(new_name, new_age, new_email)
@l.log "Inseriu nova pessoa"
end
@db.query("commit")
@l.log "comitou"
rescue Mysql2::Error => e
error = Mysql2Error.new(e)
if error.deadlock?
@l.log "Deadlock: Já foi inserida recentemente"
# Poderiamos pensar em refazer a operação aqui
# insert(new_name, new_age, new_email)
end
rescue
@l.log "Erro desconhecido"
end
end
end
con = open_connection
con.query("delete from Pessoa")
con.close
10.times.map do |i|
l = ThreadLogger.new(i)
Thread.start do
begin
con = open_connection
dao = PessoaNonRecentRepeatedInsertionDAO.new(con, PessoaDAO.new(con), l)
dao.insert("Pessoa", 20, "[email protected]")
ensure
con.close
end
end
end.each(&:join)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment