Created
January 16, 2014 08:23
-
-
Save kuwabarahiroshi/8451501 to your computer and use it in GitHub Desktop.
SQL statement with subquery is consistent but not atomic.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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