在postgres中是否有办法锁定行,直到从同一系统执行下一个选择查询。还有一件事是 锁定行上没有更新过程。 < /强> 场景是这样的
如果table1包含类似
的数据id | txt
-------------------
1 | World
2 | Text
3 | Crawler
4 | Solution
5 | Nation
6 | Under
7 | Padding
8 | Settle
9 | Begin
10 | Large
11 | Someone
12 | Dance
如果sys1执行
select * from table1 order by id limit 5;
然后它应该锁定从id 1到5的行,以便同时执行select语句的其他系统。
稍后如果sys1再次执行另一个选择查询,如
select * from table1 where id>10 order by id limit 5;
然后应该释放锁定的行。
答案 0 :(得分:4)
我不认为这是可能的。您无法阻止对表的只读访问(除非该选择已完成FOR UPDATE
)
据我所知,你唯一的机会就是使用pg_advisory_lock()
功能。
http://www.postgresql.org/docs/current/static/functions-admin.html#FUNCTIONS-ADVISORY-LOCKS
但这需要“手动”释放通过它获得的锁。你不会自动解锁。
要锁定行,您需要这样的内容:
select pg_advisory_lock(id), * from ( select * table1 order by id limit 5 ) t
(注意使用LIMIT部分的派生表。请参阅我发布的手册链接以获得解释)
然后,您需要存储检索到的ID,然后为每个ID调用pg_advisory_unlock()
。
如果每个流程始终一次发布所有 ID,则只需使用pg_advisory_unlock_all()
即可。然后,您不需要存储检索到的ID。
请注意,不会阻止其他人使用“普通”选择来读取行。只有访问该表的每个进程使用相同的获取锁的模式时,它才会起作用。
答案 1 :(得分:0)
看起来你真的有一个超越数据库边界的事务,所有的变化都发生在另一个系统中。
我的想法是select ... for update no wait
锁定相关的行,然后将数据卸载到另一个系统,然后rollback
解锁行。没有两个select ... for update
查询将选择同一行,第二个select
将立即失败而不是等待并继续。
但是你似乎没有以任何方式标记卸载的记录;我不明白为什么两个非连续选择不会愉快地选择重叠范围。所以我仍然update
带有标志和/或目标用户名的记录,并且只选择未设置标志的记录。
答案 2 :(得分:0)
我尝试了选择...进行更新和 pg_try_advisory_lock ,并设法接近我的要求。
/*rows are locking but limit is the problem*/
select * from table1 where pg_try_advisory_lock( id) limit 5;
.
.
$_SESSION['rows'] = $rowcount; // no of row to process
.
.
/*afer each process of word*/
$_SESSION['rows'] -=1;
.
.
/*and finally unlock locked rows*/
if ($_SESSION['rows']===0)
select pg_advisory_unlock_all() from table1
但这有两个问题 1.由于限制将在锁定之前应用,每次相同的行试图锁定在不同的实例中 2.不确定pg_advisory_unlock_all是否会解锁当前实例或所有实例锁定的行。