2010-10-31 38 views
0

我正在使用CentOS 5.5 Linux(与Redhat 5.5相同) 库存perl v5.8.8并已安装 DBD-Pg-2.17 .1通过CPAN外壳,我使用 postgresql-server-8.4.5-1PGDG.rhel5和朋友。具有DBD :: Pg的异步查询失败,并且:无法执行,直到上一个异步查询完成

我编写了一个简单的测试用例,演示了 我的问题 - 它列在底部。

我的代码工作正常,当我删除{pg_async => PG_ASYNC}

我的背景是,我有一个小的Facebook游戏 运行作为非分叉的Unix守护进程IO ::投票。 我想为球员添加一些统计数据,但我不想限制我的轮询循环,所以我想 喜欢发送大部分INSERT/UPDATE命令 asynchronously并且我不需要任何返回值 从数据库 - 因为阅读/显示 统计我将有单独的网页脚本。

令人惊讶的我得到错误信息 DBD :: PG :: ST执行失败:无法执行,直到前面的异步查询,即使我不使用PG_OLDQUERY_WAIT完成

这里是我的代码(我的守护进程应该重新 到PostgreSQL每当连接丢失, 这就是为什么我用* _cached方法和不退出对的eval {....}例外):

#!/usr/bin/perl -w 

use strict; 
use DBI; 
use DBD::Pg qw(:async); 

use constant DBNAME => 'snake'; 
use constant DBUSER => 'snake'; 
use constant DBPASS => 'snake'; 

use constant SQL_CREATE_TABLES => q{ 
     /* 
     create table pref_users (
       id varchar(32) primary key, 
       first_name varchar(32), 
       last_name varchar(32), 
       female boolean, 
       avatar varchar(128), 
       city varchar(32), 
       lat real check (-90 <= lat and lat <= 90), 
       lng real check (-90 <= lng and lng <= 90), 
       last_login timestamp default current_timestamp, 
       last_ip inet, 
       medals smallint check (medals > 0) 
     ); 

     create table pref_rate (
       obj varchar(32) references pref_users(id), 
       subj varchar(32) references pref_users(id), 
       good boolean, 
       fair boolean, 
       nice boolean, 
       about varchar(256), 
       last_rated timestamp default current_timestamp 
     ); 

     create table pref_money (
       id varchar(32) references pref_users, 
       yw char(7) default to_char(current_timestamp, 'YYYY-WW'), 
       money real 
     ); 
     create index pref_money_yw_index on pref_money(yw); 

     create table pref_pass (
       id varchar(32) references pref_users 
     ); 

     create table pref_misere (
       id varchar(32) references pref_users 
     ); 
     */ 

     create or replace function pref_update_users(_id varchar, 
      _first_name varchar, _last_name varchar, _female boolean, 
      _avatar varchar, _city varchar, _last_ip inet) returns void as $BODY$ 
       begin 

       update pref_users set 
        first_name = _first_name, 
        last_name = _last_name, 
        female = _female, 
        avatar = _avatar, 
        city = _city, 
        last_ip = _last_ip 
       where id = _id; 

       if not found then 
         insert into pref_users(id, first_name, 
          last_name, female, avatar, city, last_ip) 
         values (_id, _first_name, _last_name, 
          _female, _avatar, _city, _last_ip); 
       end if; 
       end; 
     $BODY$ language plpgsql; 
}; 

eval { 
     my $dbh = DBI->connect_cached('dbi:Pg:dbname=' . 
      DBNAME, DBUSER, DBPASS, { 
      AutoCommit => 1, 
      PrintWarn => 1, 
      PrintError => 1, 
      RaiseError => 1, 
      FetchHashKeyName => 'NAME_lc', 
      pg_enable_utf8 => 1 
     }, {pg_async => PG_ASYNC}); 

     $dbh->do(SQL_CREATE_TABLES, {pg_async => PG_ASYNC}); 
}; 
warn [email protected] if [email protected]; 

for my $i (1..10) { 
     eval { 
       my $dbh = DBI->connect_cached('dbi:Pg:dbname=' . 
        DBNAME, DBUSER, DBPASS, { 
        AutoCommit => 1, 
        PrintWarn => 1, 
        PrintError => 1, 
        RaiseError => 1, 
        FetchHashKeyName => 'NAME_lc', 
        pg_enable_utf8 => 1 
       }, {pg_async => PG_ASYNC}); 

       #$dbh->pg_result; 

       my $sth = $dbh->prepare_cached(
        q{select pref_update_users(?, ?, ?, ?, ?, ?, NULL)}, {pg_async => PG_ASYNC}); 

       $sth->execute('ID123', 'Alexander', 'Farber', undef, undef, undef); 
     }; 
     warn [email protected] if [email protected]; 
} 

谢谢 亚历

+1

会在'eval {};'块后面提到'$'警告$'''为什么你没有检查'eval'错误? – mfontani 2010-10-31 23:36:11

+0

你好,“警告$ @ if $ @;”打印完全相同的字符串作为PrintError,这就是为什么我省略它 – 2010-11-01 08:48:06

+0

我已经添加warn $ @到我的代码并评论表的创建,但它不这里真的改变了一切。 – 2010-11-01 08:53:50

回答

2

DBD :: PG的异步支持的作品那样,只有一个活动在时间异步查询。如果要取消或等待当前活动查询,然后执行新查询,而不是抛出有关旧查询的错误,则需要将PG_OLDQUERY_CANCEL和PG_OLDQUERY_WAIT常量设置为开。

您可以将您的查询添加到AoH(Array of Hashes)或Thread::Queue(忽略该名称,它作为通用队列对象很有用,并在定时器上执行它们(一旦前一个已完成)(或添加将$ dbh - > {pg_socket}套接字添加到使用IO :: Poll的轮询套接字中,并检查您的查询的准备情况,并在该套接字有数据读取时执行队列中的下一个查询,表明与pg_ready相同)