ロックとトランザクションの検証
検証結果
lockしたレコードはtransactionがcommitされるまでロックされ続ける。
実行結果
| コンソール1 | コンソール2 | |—————————–|————————–| | 検索前: 03:01:03.185, 100 | ↓ | | 検索後: 03:01:03.188, 100 | ↓ | | ロック前: 03:01:03.189, 100 | ↓ | | ロック後: 03:01:03.193, 100 | ↓ | | スリープ前: 03:01:03.194, 100 | ↓ | | ↓ | 検索前: 03:01:04.203, 100 | | ↓ | 検索後: 03:01:04.208, 100 | | ↓ | ロック前: 03:01:04.210, 100 | | スリープ後: 03:01:08.201, 100 | ↓ | | 更新前: 03:01:08.207, 100 | ↓ | | 更新後: 03:01:08.216, 0 | ↓ | | スリープ前: 03:01:08.218, 0 | ↓ | | スリープ後: 03:01:13.197, 0 | ↓ | | ロールバック前: 03:01:13.203, 0 | ↓ | | ↓ | ロック後: 03:01:13.210, 100 | | ↓ | 更新前: 03:01:13.213, 100 | | ロールバック後: 03:01:13.219, 100 | ↓ | | | 更新後: 03:01:13.220, 50 |
検証に用いたコード
コンソール1で実行(first_execution)
def now; Time.now.strftime("%H:%M:%S.%L"); end
def tagging(action, timeline)
timeline << "#{action}前: #{now}, #{point}"
value = yield
timeline << "#{action}後: #{now}, #{point}"
return value
end
def point
UserPoint.find(1).point
end
def first_execution
timeline = []
rup = UserPoint.find(1)
rup.assign_attributes(point: 100)
rup.save!
begin
ApplicationRecord.transaction do
user_point = tagging("検索", timeline, &-> () { UserPoint.find(1) })
tagging("ロック", timeline, &-> () { user_point.lock! })
tagging("スリープ", timeline, &-> () { sleep 5 })
user_point.point = user_point.point - 100
tagging("更新", timeline, &-> () { user_point.save! })
tagging("スリープ", timeline, &-> () { sleep 5 })
tagging("ロールバック", timeline, &-> () { raise ActiveRecord::Rollback })
end
ensure
timeline << "ロールバック後: #{now}, #{point}"
puts timeline
end
end
コンソール2で実行(second_execution)
def now; Time.now.strftime("%H:%M:%S.%L"); end
def tagging(action, timeline)
timeline << "#{action}前: #{now}, #{point}"
value = yield
timeline << "#{action}後: #{now}, #{point}"
return value
end
def point
UserPoint.find(1).point
end
def second_execution
timeline = []
begin
ApplicationRecord.transaction do
user_point = tagging("検索", timeline, &-> () { UserPoint.find(1) })
tagging("ロック", timeline, &-> () { user_point.lock! })
user_point.point = user_point.point - 50
tagging("更新", timeline, &-> () { user_point.save! })
end
ensure
puts timeline
end
end