锁定行直到下一步选择postgres

时间:2011-01-01 10:31:13

标签: postgresql select locking

在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;

然后应该释放锁定的行。

3 个答案:

答案 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是否会解锁当前实例或所有实例锁定的行。