Postgresql和PHP:在多用户应用程序中,currval是否是检索最后插入行的ID的有效方式?

3

我在想,我用来获取postgresql表中最后一行插入的id的方法是否有效。

这个方法当然可以工作,但是当我有很多用户同时向同一张表添加行时,引用序列currval值可能会有问题。

我的实际方法是:

$pgConnection = pg_connect('host=127.0.0.1 dbname=test user=myuser password=xxxxx')or die('cant connect');

$insert = pg_query("INSERT INTO customer (name) VALUES ('blabla')");
$last_id_query = pg_query("SELECT currval('customer_id_seq')");
$last_id_results = pg_fetch_assoc($last_id_query);
print_r($last_id_results);
pg_close($pgConnection);

目前只是一个测试。 但是,我可以看到这种方式存在三个问题:

  1. 引用customer_id_seq,如果两个用户在同一时间做相同的事情,可能会发生他们都从那里获得相同的id...或者不会?
  2. 我必须知道表序列的名称。因为pg_get_serial_sequence对我不起作用(我是postgresql上的新手,可能是配置问题)。

有什么建议/更好的方法吗?

p.s:我不能使用PDO,因为它似乎在事务保存点方面缺少了一些内容;我不想使用Zend,最后,我更喜欢使用PHP pg_*函数(也许最终我会构建我的类)

编辑:

@SpliFF(thet删除了他的回答):这样会更好吗?

$pgConnection = pg_connect('host=127.0.0.1 dbname=test user=myuser password=xxxxx')or die('cant connect');

pg_query("BEGIN");

$insert = pg_query("INSERT INTO customer (name) VALUES ('blabla')");

$last_id_query = pg_query("SELECT currval('customer_id_seq')");

$last_id_results = pg_fetch_assoc($last_id_query);

print_r($last_id_results);

//do somethings with the new customer id

pg_query("COMMIT");

pg_close($pgConnection);
3个回答

7
如果您使用的是较新版本的PostgreSQL(> 8.1),则应该使用INSERT(和UPDATE)命令的RETURNING子句。
另一方面,如果您坚持使用序列操作函数之一,请阅读fine manual。提示:“请注意,因为这返回一个会话本地值,所以它无论其他会话是否执行了nextval,都会给出可预测的答案。”

我不想使用序列操作函数 - 但实际上 - 它们似乎是在不使用PDO的情况下检索最后一个ID的唯一方法! - Strae
如果我正在使用PostgreSQL-7.4,而且我无法升级怎么办? - Strae
1
7.4版本已经过时了。几乎没有人会再支持它;如果在7.4中发布一个错误到开发者列表,他们只会嘲笑你。 - kquinn
因为你正在使用旧版本的Debian(4.0附带pgsql 7.4),你必须使用backports.org或升级到Debian 5.0,该版本附带pgsql 8.3。 - Milen A. Radev
DaNieL - 请检查 Milen 回答中的 "OTOH" 部分。基本上,currval() 在每个 PostgreSQL 上都是安全的。 - user80168
显示剩余3条评论

1
在一个事务中插入和检查curval(seq)。在提交事务之前,您将看到您的查询的curval(seq),无论谁在同一时间插入。
不记得语法确切的样子 - 在手册中阅读(大约3年前使用过pgsql),但通常是这样的:
BEGIN TRANSACTION;
INSERT ...;
SELECT curval(seq);
COMMIT;

嗯...但是如果两个事务同时发生,currval值不会相同吗? - Strae
不。每个事务都安全地运行在它自己的状态下,然后pgsql将所有事务结果刷新到硬盘上的表中。这就是为什么发明了事务的原因 ;)。 - Jet
事务与currval无关。 - user80168
好的,使用"SELECT MAX(id)"或者"SELECT id ORDER BY id DESC LIMIT 1"代替...实际上,我不确定currval() - 不记得确切的内容了。但是在事务期间,表中的值必须是实际的以获得准确的状态,而不是所有服务器都是如此。因此,在事务内部,您可以获取最后一个查询的真实insert_id。 - Jet

-1

例如:插入到日志(描述,用户ID)值('drop her mind',6),返回ID


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接