Php pg_send_query():无法将连接设置为阻止模式?
我有一个长期运行的脚本,它似乎偶尔会报告以下通知级别的错误: pg_send_query():无法将连接设置为阻止模式 之后它似乎会继续发送查询,但不清楚它是否成功发送了生成错误的查询 这是什么症状 编辑:错误发生时,postgres日志中没有任何条目,这表明这仅仅是一个连接错误,而不是postgres方面的错误(例如,可能不是postgres崩溃和重新启动或其他原因造成的) 编辑:据我所知,当触发此错误时,我的INSERT语句以某种方式成功Php pg_send_query():无法将连接设置为阻止模式?,php,postgresql,Php,Postgresql,我有一个长期运行的脚本,它似乎偶尔会报告以下通知级别的错误: pg_send_query():无法将连接设置为阻止模式 之后它似乎会继续发送查询,但不清楚它是否成功发送了生成错误的查询 这是什么症状 编辑:错误发生时,postgres日志中没有任何条目,这表明这仅仅是一个连接错误,而不是postgres方面的错误(例如,可能不是postgres崩溃和重新启动或其他原因造成的) 编辑:据我所知,当触发此错误时,我的INSERT语句以某种方式成功 编辑:看起来这可能在2013年6月得到了修复:听起来
编辑:看起来这可能在2013年6月得到了修复:听起来您正试图使用
pg\u send\u query()
函数向PostgreSQL发送异步查询。此函数的目的是允许PHP脚本在等待PostgreSQL执行查询并准备好结果的同时继续执行其他代码
forpg\u send\u query()
中给出的示例建议,如果PostgreSQL已经在处理另一个查询,则不应发送查询:
if (!pg_connection_busy($dbconn)) {
pg_send_query($dbconn, "select * from authors; select count(*) from authors;");
}
您使用
pg\u send\u query()
而不是pg\u query()
有什么原因吗?如果您可以允许脚本阻止等待查询执行,我猜(当然没有尝试过)您不会看到这些错误。这是pg\u send\u query()
无法成功地将连接切换回阻止模式的症状。查看PHPs pgsql.c中的源代码,您可以找到:
/* {{{ proto bool pg_send_query(resource connection, string query)
Send asynchronous query */
PHP_FUNCTION(pg_send_query)
{
<... snipped function setup stuff ...>
if (PQ_SETNONBLOCKING(pgsql, 1)) {
php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Cannot set connection to nonblocking mode");
RETURN_FALSE;
}
<... snipped main function execution stuff ...>
if (PQ_SETNONBLOCKING(pgsql, 0)) {
php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Cannot set connection to blocking mode");
}
RETURN_TRUE;
}
如果arg为1,则将连接状态设置为非阻塞,
或在arg为0时阻塞。如果是,则返回0
好的,如果有错误,-1
在非阻塞状态下,调用
PQsendQuery、PQputline、PQputnbytes、,
和PQendcopy将不会阻止,但
如果需要,则返回一个错误
再次被召唤
请注意,PQexec不遵守
非阻塞模式;如果它被称为
不管怎么说,他都会采取封锁的方式
进一步查看PQsetnonblocking的来源(在PostgeSQLs fe exec.c中),调用失败可能有两个原因:
/* PQsetnonblocking:
* sets the PGconn's database connection non-blocking if the arg is TRUE
* or makes it non-blocking if the arg is FALSE, this will not protect
* you from PQexec(), you'll only be safe when using the non-blocking API.
* Needs to be called only on a connected database connection.
*/
int
PQsetnonblocking(PGconn *conn, int arg)
{
bool barg;
if (!conn || conn->status == CONNECTION_BAD)
return -1;
barg = (arg ? TRUE : FALSE);
/* early out if the socket is already in the state requested */
if (barg == conn->nonblocking)
return 0;
/*
* to guarantee constancy for flushing/query/result-polling behavior we
* need to flush the send queue at this point in order to guarantee proper
* behavior. this is ok because either they are making a transition _from_
* or _to_ blocking mode, either way we can block them.
*/
/* if we are going from blocking to non-blocking flush here */
if (pqFlush(conn))
return -1;
conn->nonblocking = barg;
return 0;
}
因此,要么连接不知何故丢失,要么pqFlush没有成功完成,这表明连接输出缓冲区中存在剩余内容
第一种情况是无害的,因为您的脚本肯定会在以后的调用中注意到丢失的连接,并对此做出反应(或者更明显地失败)
这就剩下了第二种情况,这意味着您的连接处于非默认、非阻塞状态。我不知道这是否会影响以后重用此连接的调用。如果您想安全起见,在这种情况下,您应该关闭连接并使用新的/另一个连接。如果您使用线程,并且重新使用连接,则可能会发生这种情况。 如果是这种情况,您可以像这样使用
PGSQL\u CONNECT\u FORCE\u NEW
:
pg_connect("...", PGSQL_CONNECT_FORCE_NEW)
这将强制使用新的数据库连接资源,但请注意:您可能会耗尽客户端的连接,因此请小心地在线程内部使用此资源,以便不要忘记使用
pg_close()
我最近遇到了相同的问题,在Henrik Opels的帮助下,answer意识到PHP实际上不会等到缓冲区刷新后再将连接设置回阻塞模式
“无法将连接设置为阻塞模式”对于足够大的查询可以重复,以填充发送缓冲区(在末尾填充空格就足够了)。对于较小的查询,我认为它取决于负载,而且是断断续续的
如果您确实需要异步模式,请尝试在上的补丁。我在PHP5.6.9中遇到了相同的错误消息 当pg_pconnect()建立的持久连接丢失且 pgsql.auto_reset_persistent设置为Off 在以下情况下,连接可能会丢失:
启用pgsql.auto_reset_persistent后,每次调用pg_pconnect()时,都会检查连接链接是否仍然有效。这需要一点开销,但会在连接丢失时修复错误消息。我也遇到了这个错误。我通过重新启动web服务器(Apache)来解决我的问题。+1-考虑到“长时间运行脚本”的说法,我假设他是故意异步执行的,但如果不是这样的话,这将是显而易见的解决方案:)需要使用
pg\u send\u query()
才能在查询失败时正确查询错误。否则,您需要使用pg\u last\u error()
,但实际效果并不理想。如果您使用pg\u send\u query()
并与远程服务器对话,请注意错误。如果查询字符串太长(以字节为单位),pg\u send\u query()
将因实现错误而失败(触摸连接前缺少刷新)。对于解决方法,请安装PgBouncer并使用pg_connect()连接到本地主机PgBouncer,而不是直接连接到远程服务器。+1用于确定真正的原因并提供实际的建议。做得好!我想我很不幸地用pg_query()和pg_pconnect()组合成功地重复了这个错误。不需要使用pg_send_query()。如果使用pg_pconnect()获取“新”连接时自动回滚上一个连接,则pg_查询似乎会随机生成此错误。在Ubuntu10.04 LTS x86-64上运行的PHP 5.3.2和Postgres 8.4存在问题。如果您遇到此问题,并且没有尝试使用pg_pconnect()
可能的原因是PHP错误:您还可以在本地主机和
pg_connect("...", PGSQL_CONNECT_FORCE_NEW)