Skip to content

Instantly share code, notes, and snippets.

@kuwabarahiroshi
Created January 16, 2014 08:23
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kuwabarahiroshi/8451501 to your computer and use it in GitHub Desktop.
Save kuwabarahiroshi/8451501 to your computer and use it in GitHub Desktop.
SQL statement with subquery is consistent but not atomic.
#!/usr/bin/env ruby
require 'mysql2'
#------------------------------------
# config
#------------------------------------
MYSQL_CONF = {
host: 'localhost',
username: 'root',
password: '',
database: 'test'
}
#------------------------------------
# setup
#------------------------------------
Mysql2::Client.new(MYSQL_CONF).tap do |cli|
cli.query 'drop table if exists likes;'
cli.query 'drop table if exists photos;'
cli.query 'drop table if exists users;'
cli.query 'create table likes ( user_id INT, photo_id INT, created_at timestamp default current_timestamp, primary key (user_id, photo_id) );'
cli.query 'create table photos ( id INT AUTO_INCREMENT PRIMARY KEY, likes_count INT );'
cli.query 'create table users ( id INT AUTO_INCREMENT PRIMARY KEY, name varchar(255) );'
cli.query 'insert into photos set likes_count = 0;'
cli.query "insert into users set name = 'A';"
end
#------------------------------------
# like action
#------------------------------------
def like(user_id, photo_id)
cli = Mysql2::Client.new(MYSQL_CONF)
begin
p 'begin!!'
cli.query 'BEGIN'
cli.query <<-EOS
update photos
set likes_count = likes_count+1
where not exists (
select 1 from likes where user_id = #{user_id} and photo_id = #{photo_id}
);
EOS
cli.query <<-EOS
insert into likes (user_id, photo_id)
select #{user_id}, #{photo_id}
from dual
where not exists (
select 1 from likes
where user_id = #{user_id}
and photo_id = #{photo_id}
);
EOS
cli.query 'COMMIT'
p 'commit!!!'
rescue => e
cli.query 'ROLLBACK'
p 'rollback!!!'
p e
end
end
#------------------------------------
# 3 parallel request
#------------------------------------
(1..3).map do
Thread.new {
like(1, 1)
}
end.each do |t|
t.join
end
#------------------------------------
# result
#------------------------------------
Mysql2::Client.new(MYSQL_CONF).tap do |cli|
p '== likes =='
cli.query('select * from likes;').each do |row| p row; end
p '== photos =='
cli.query('select * from photos;').each do |row| p row; end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment