Post

ロックとトランザクションの検証

検証結果

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
This post is licensed under CC BY 4.0 by the author.