Chinaunix

标题: pg 不能存储过程当中锁某一行? [打印本页]

作者: udbjqr    时间: 2009-04-20 22:48
标题: pg 不能存储过程当中锁某一行?
使用PGsql,就是冲着它跟oracle一样可以进行行锁定去的,结果在写存储过程的时候告诉我不能在存储过程当中使用for update/share.....这这这..存储过程内不能使用事务也就算了,基本代码写好点也能过去,但不能锁行这个就太说不过去了吧.难道是我没找到方法.....
作者: udbjqr    时间: 2009-04-20 23:58
总算被我找到了方法...可以在function里面使用了.....虽然不是特别好用,而且需要注意的特别多.
作者: scottsiu    时间: 2009-04-21 21:26
标题: 回复 #1 udbjqr 的帖子
官方的说法是:
FOR UPDATE causes the rows retrieved by the SELECT statement to be locked as though for update. This prevents them from being modified or deleted by other transactions until the current transaction ends. That is, other transactions that attempt UPDATE, DELETE, or SELECT FOR UPDATE of these rows will be blocked until the current transaction ends.

也就是说,只要在一个transaction中就可以用,不一定是function/procedure。
作者: udbjqr    时间: 2009-04-21 22:42
这一行说的没错,也就是说如果你使用
begin;
  select * from table1 where id = 1 for update;
  ......
commit;

这样的写法,在这个事务当中这一行是被锁定的.直至事务结束.

但还有一段是告诉我,不能在一个plpgsql的funtion里面使用for update/share.这样的方法去锁一个行.我要的是在存储过程里面执行这样的锁行动作.前面的代码是可以执行的,但不能放在function ()里面.这样的限制好奇怪.我不放在存储过程里面我要锁单行的动作有什么意义.一般也没有谁写大段的sql代码而不用存储过程的吧.

倒是在网上找到一个解决方案,是使用 pg_advisory_lock来锁单行.但这个锁好奇怪,不是sql的标准锁.没有底的东西,不太敢用.....
再有就是直接在事务开始的时候更新行...这个方案还是我一个同事想出来的.想想也对,我直接update这一行,他存储过程总应该就锁住了吧.反正一个存储过程也不让我写commit或rollback savepoint 这样的东西..直接执行到最后,好在pgsql如果执行出错会回滚整个存储过程,不象sqlserver,在哪一行出错这一行不执行..前面的就不管了.....
作者: trainee    时间: 2009-04-22 08:44
但还有一段是告诉我,不能在一个plpgsql的funtion里面使用for update/share.这样的方法去锁一个行.我要的是在存储过程里面执行这样的锁行动作.前面的代码是可以执行的,但不能放在function ()里面.这样的限制好奇怪.我不放在存储过程里面我要锁单行的动作有什么意义.一般也没有谁写大段的sql代码而不用存储过程的吧..


你从哪里看的? 你误解了

我从来没看到 有这限制
作者: udbjqr    时间: 2009-04-22 08:51
好吧.我承认..的确我也没有在任何一个文档中看到,只在官网的邮件列表里面有看到说明,你把下面的代码拿出来执行一下你就知道了.看看异常提示哟
CREATE OR REPLACE FUNCTION f_getpasswd(len integer)
  RETURNS void AS
$BODY$
declare
begin
--就这一句了.
  select * from s_users where userid = 1 for update;

end;
$BODY$
  LANGUAGE 'plpgsql'
作者: scottsiu    时间: 2009-04-22 19:35
标题: 回复 #6 udbjqr 的帖子
我测试运行正常,我的理解是在Function或Procedure中如果要用select的话要不就是在游标中使用,要不就是select...into。
如果只有一句select ename from emp where empno = 7521,在运行时会出现以下错误:
ERROR: query has no destination for result data
SQL 状态: 42601
指导建议:If you want to discard the results of a SELECT, use PERFORM instead.
上下文L/pgSQL function "f_getpasswd" line 5 at SQL statement


我在EDB PPAS 8.3(相当于PostgreSQL 8.3内核)中测试如下:

CREATE OR REPLACE FUNCTION f_getpasswd(len integer)
  RETURNS char AS
$BODY$
declare
  v_name emp.ename%TYPE;
begin
--就这一句了.
  select ename into v_name from emp where empno = 7521 for update;
  return v_name;
end;
$BODY$
LANGUAGE 'plpgsql'

select f_getpasswd(2);
作者: udbjqr    时间: 2009-04-23 14:40
果然是可以,看样子果然还是在存储过程里面不能写单独的select语句..呵呵.十分感谢.
作者: scottsiu    时间: 2009-04-24 15:59
You are welcome!
作者: zonyuan    时间: 2009-04-27 11:40
我这里也使用正常啊.




欢迎光临 Chinaunix (http://bbs.chinaunix.net/) Powered by Discuz! X3.2