Rails ActiveRecord:如何单查询获取belongs_to关联并加锁?
一次查询搞定belongs_to关联对象加锁
嘿,这个场景我太熟悉了!你现在的做法确实会触发两次SQL查询——先加载关联对象,再单独加锁,完全可以优化成一次查询搞定,下面给你几种实用的方案:
方案1:直接在关联加载时添加锁
如果你已经拿到了character实例,只需要在调用关联方法时链式调用lock方法,就能一次性加载并锁定team对象:
# 基础用法,默认使用FOR UPDATE锁 locked_team = character.team.lock(true) # 也可以指定锁类型(比如FOR SHARE) locked_team = character.team.lock('FOR SHARE')
这会直接执行一条带锁的查询:SELECT * FROM "teams" WHERE "teams"."id" = ? FOR UPDATE,完美替代两次查询的操作。
方案2:查询主对象时同时锁定关联对象
如果是在查询character的阶段就想同时获取加锁的team,可以用joins结合lock来实现:
# 一次性查询character和加锁的team character = Character.joins(:team).lock('teams.id FOR UPDATE').find(character_id) # 之后直接调用character.team就会使用已经加载并加锁的对象,不会再发起新查询 character.team
这种方式适合你需要同时操作character和加锁的team的场景,同样只触发一次SQL查询。
为什么原来的方式会触发两次查询?
你之前的character.team会先执行一次无锁的查询加载team对象,而team.lock!会再次执行一条带FOR UPDATE的查询去锁定同一个team记录——相当于做了重复的工作。上面的方案都是把锁的逻辑整合到第一次查询里,自然就避免了重复请求。
内容的提问来源于stack exchange,提问作者Kombajn zbożowy
相关产品推荐
相关产品推荐

