PG::ERROR: 另一个命令正在进行中

5
我是一名有用的助手,可以为您翻译文本。
我有一个导入工具,它可以将电子邮件列表保存到Postgres数据库中。以下是一个不包含表格的导入器类中的代码片段:
query_temporary_table = "CREATE TEMPORARY TABLE subscriber_imports (email CHARACTER VARYING(255)) ON COMMIT DROP;"
query_copy            = "COPY subscriber_imports(email) FROM STDIN WITH CSV;"
query_delete          = "DELETE FROM subscriber_imports WHERE email IN (SELECT email FROM subscribers WHERE suppressed_at IS NOT NULL OR list_id = #{list.id}) RETURNING email;"
query_insert          = "INSERT INTO subscribers(email, list_id, created_at, updated_at) SELECT email, #{list.id}, NOW(), NOW() FROM subscriber_imports RETURNING id;"

conn = ActiveRecord::Base.connection_pool.checkout
conn.transaction do
  raw = conn.raw_connection

  raw.exec(query_temporary_table)
  raw.exec(query_copy)
  CSV.read(csv.path, headers: true).each do |row|
    raw.put_copy_data row['email']+"\n" unless row.nil?
  end
  raw.put_copy_end
  while res = raw.get_result do; end # very important to do this after a copy

  result_delete = raw.exec(query_delete)
  result_insert = raw.exec(query_insert)

  ActiveRecord::Base.connection_pool.checkin(conn)
  {
    deleted:  result_delete.count,
    inserted: result_insert.count,
    updated:  0
  }
end

我遇到的问题是在上传时出现了异常:

当我尝试上传时,会出现一个异常:

PG::ERROR: another command is already in progress: ROLLBACK

这一切都在一个动作中完成,我正在进行的其他查询仅涉及用户验证,而我使用了DB互斥锁来防止重叠导入。这个查询之前一直正常工作,直到我最近的推送,其中包括将我的pg gem从0.13.2更新到0.14.1(以及其他“无关”的代码)。
错误最初发生在我们的staging服务器上,但后来我能够在本地重现它,现在也束手无策了。
如果我的问题需要更加清晰明了,请告诉我。
谢谢。
1个回答

13

我找到了自己的答案,如果其他人在使用"复制"导入大量数据时遇到相同问题,这可能会有用。

在CSV.read()块中会抛出异常,我捕获了它,但是没有正确结束进程。

  begin
    CSV.read(csv.path, headers: true).each do |row|
      raw.put_copy_data row['email']+"\n" unless row.nil?
    end
  ensure
    raw.put_copy_end
    while res = raw.get_result do; end # very important to do this after a copy
  end

这个块确保COPY命令已经完成。我还在最后添加了这个块,以释放连接回到池中,在成功导入的情况下不会破坏流程:

rescue
  ActiveRecord::Base.connection_pool.checkin(conn)

3
pg库的示例目录中,还有一个更完整的示例,展示了如何使用原始PG连接完成此操作。它添加了错误处理,并展示了如何使用从#get_result获得的Result对象。 - Michael Granger
只是补充一下,如果您使用现有的连接,则不需要checkin(conn):conn = ActiveRecord::Base.connection - Jonathan Buyco
谢谢,这对我非常有帮助 :) - Blue Smith

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