【问题标题】:Rails + Postgres drop error: database is being accessed by other usersRails + Postgres 丢弃错误:其他用户正在访问数据库
【发布时间】:2011-01-23 02:35:02
【问题描述】:

我有一个在 Postgres 上运行的 rails 应用程序。

我有两台服务器:一台用于测试,另一台用于生产。

我经常需要在测试服务器上克隆生产数据库。

我通过 Vlad 运行的命令是:

rake RAILS_ENV='test_server' db:drop db:create

我遇到的问题是我收到以下错误:

ActiveRecord::StatementInvalid: PGError: ERROR: database <database_name> is being accessed by other users DROP DATABASE IF EXISTS <database_name>

如果有人最近通过网络访问了应用程序,就会发生这种情况(postgres 保持“会话”打开)

有什么方法可以终止 postgres DB 上的会话?

谢谢。

编辑

我可以使用 phppgadmin 的界面删除数据库,但不能使用 rake 任务。

如何通过 rake 任务复制 phppgadmin 的 drop?

【问题讨论】:

  • 确保您没有与数据库的连接,否则它不会丢弃它。查看更多关于this here的信息。

标签: ruby-on-rails postgresql


【解决方案1】:

如果您终止应用程序正在运行的 postgresql 连接,则可以正常运行 db:drop。那么如何杀死这些连接呢?我使用以下 rake 任务:

# lib/tasks/kill_postgres_connections.rake
task :kill_postgres_connections => :environment do
  db_name = "#{File.basename(Rails.root)}_#{Rails.env}"
  sh = <<EOF
ps xa \
  | grep postgres: \
  | grep #{db_name} \
  | grep -v grep \
  | awk '{print $1}' \
  | xargs kill
EOF
  puts `#{sh}`
end

task "db:drop" => :kill_postgres_connections

在您下次尝试加载页面时,从导轨下终止连接有时会导致它崩溃,但再次重新加载会重新建立连接。

【讨论】:

  • 我不得不将 sudo 添加到 xargs 并更改数据库名称,但它可以工作。 TY
  • 我也一样...更改为“sudo xargs kill”并将 db_name 硬编码为“my-development-database-name”
  • task "db:drop" =&gt; :kill_postgres_connections 我认为应该删除这条线,在我看来,扩展系统任务的行为是危险的。
  • 与其硬编码您的数据库名称,不如使用以下代码:db_name = Rails.configuration.database_configuration[Rails.env]['database']
【解决方案2】:

更简单和更新的方法是: 1.使用ps -ef | grep postgres查找连接# 2.sudo kill -9 "# of the connection

注意:可能存在相同的 PID。杀一杀一杀。

【讨论】:

  • 结果中哪个数字代表PID?我看到 3 个未标记的列,其中的数字看起来像 PID。
  • @BradGreens 第二栏(我使用的是 Mac 终端)
  • 用 ps 找不到任何东西,但仍然在 db:drop 上得到错误。
【解决方案3】:

这里有一个快速的方法来杀死你的 postgres 数据库的所有连接。

sudo kill -9 `ps -u postgres -o pid` 

警告:这将杀死 postgres 用户打开的所有正在运行的进程,因此请确保您要先执行此操作。

【讨论】:

  • 在我的系统中,我改用sudo kill -9 `ps -u postgres -o pid=` ,所以ps不会打印PID标头,因此不会将字符串参数传递给kill ,因此不会引发错误。无论如何都是很棒的提示。
  • 我不断得到赞成和反对,导致评分接近于零。似乎是一个有争议的“快速修复”。让我郑重声明,我确实发出了危险警告。 :)
  • 如果你在 Ubuntu 上使用这个来重新启动 postgresql:sudo service postgresql start
【解决方案4】:

我使用以下 rake 任务来覆盖 Rails drop_database 方法。

lib/database.rake

require 'active_record/connection_adapters/postgresql_adapter'
module ActiveRecord
  module ConnectionAdapters
    class PostgreSQLAdapter < AbstractAdapter
      def drop_database(name)
        raise "Nah, I won't drop the production database" if Rails.env.production?
        execute <<-SQL
          UPDATE pg_catalog.pg_database
          SET datallowconn=false WHERE datname='#{name}'
        SQL

        execute <<-SQL
          SELECT pg_terminate_backend(pg_stat_activity.pid)
          FROM pg_stat_activity
          WHERE pg_stat_activity.datname = '#{name}';
        SQL
        execute "DROP DATABASE IF EXISTS #{quote_table_name(name)}"
      end
    end
  end
end

【讨论】:

  • 你读过那个生产警告吗?只是好奇:P
【解决方案5】:

当我们使用上面的“kill processes”方法时,db:drop 失败了(如果 :kill_postgres_connections 是先决条件)。我相信这是因为 rake 命令正在使用的连接被杀死。相反,我们使用 sql 命令断开连接。这是 db:drop 的先决条件,避免了通过相当复杂的命令杀死进程的风险,并且它应该适用于任何操作系统(gentoo 需要不同的 kill 语法)。

cmd = %(psql -c "SELECT pg_terminate_backend(procpid) FROM pg_stat_activity WHERE procpid <> pg_backend_pid();" -d '#{db_name}')

这是一个 rake 任务,它从 database.yml 读取数据库名称并运行改进的(恕我直言)命令。它还添加了 db:kill_postgres_connections 作为 db:drop 的先决条件。它包含一个警告,在您升级 rails 后会大喊大叫,表明可能不再需要此补丁。

参见:https://gist.github.com/4455341,包括参考文献

【讨论】:

    【解决方案6】:

    请检查您的 Rails 控制台或服务器是否在另一个选项卡中运行,然后

    停止 Rails 服务器和控制台。

    然后运行

     rake db:drop
    

    【讨论】:

      【解决方案7】:

      让您的应用程序在完成后关闭连接。 PostgreSQL 不保持连接打开,它是应用程序保持连接。

      【讨论】:

      • 我可以使用 phppgadmin 的界面删除数据库,但不能使用 rake 任务。如何使用 rake 任务复制 phppgadmin 的 drop?
      • 抱歉,帮不了你,我没有使用 rake 的经验。但是,该错误表明另一个用户仍在使用该数据库。这就是为什么你不能删除数据库,不是通过 rake 也不是通过 PhpPgAdmin,这是不可能的。从手册中,DROP DATABASE:当您或其他任何人连接到目标数据库时,它无法执行。
      【解决方案8】:

      步骤 1

      使用ps -ef | grep postgres获取所有postgres连接的列表

      列表将如下所示:

        502   560   553   0 Thu08am ??         0:00.69 postgres: checkpointer process             
        502   565   553   0 Thu08am ??         0:00.06 postgres: bgworker: logical replication launcher
        502 45605   553   0  2:23am ??         0:00.01 postgres: st myapp_development [local] idle 
      

      第二步

      使用sudo kill -9 &lt;pid&gt; 停止您想要的任何连接,其中pid 是第二列中的值。就我而言,我想用 pid 45605 停止最后一行,所以我使用:

      sudo kill -9 45605
      

      【讨论】:

        【解决方案9】:

        Rails 可能会连接到数据库以删除它,但是当您通过 phppgadmin 登录时,它是通过 template1 或 postgres 数据库登录的,因此您不受它的影响。

        【讨论】:

        • 如何强制 rails 删除数据库?我应该使用 postgres SQL 命令定义自己的 rake 操作吗?
        【解决方案10】:

        我编写了一个名为 pgreset 的 gem,当您运行 rake db:drop(或 db:reset 等)时,它会自动终止与相关数据库的连接。您所要做的就是将它添加到您的 Gemfile 中,这个问题应该会消失。在撰写本文时,它适用于 Rails 4 及更高版本,并已在 Postgres 9.x 上进行了测试。任何感兴趣的人都可以在github 上获得源代码。

        gem 'pgreset'
        

        【讨论】:

        • 除了你的 gem 什么都不会——连接不存在(ps grep 搜索等),但 rails 认为它​​存在。非常感谢!
        【解决方案11】:

        这对我有用(rails 6): rake db:drop:_unsafe

        我认为我们的代码库中有一些东西在 rake 任务尝试删除它之前启动了一个 db 连接。

        【讨论】:

          【解决方案12】:

          您可以简单地对执行删除操作的 ActiveRecord 代码进行猴子补丁。

          对于 Rails 3.x:

          # lib/tasks/databases.rake
          def drop_database(config)
            raise 'Only for Postgres...' unless config['adapter'] == 'postgresql'
            Rake::Task['environment'].invoke
            ActiveRecord::Base.connection.select_all "select pg_terminate_backend(pg_stat_activity.pid) from pg_stat_activity where datname='#{config['database']}' AND state='idle';"
            ActiveRecord::Base.establish_connection config.merge('database' => 'postgres', 'schema_search_path' => 'public')
            ActiveRecord::Base.connection.drop_database config['database']
          end
          

          对于 Rails 4.x:

          # config/initializers/postgresql_database_tasks.rb
          module ActiveRecord
            module Tasks
              class PostgreSQLDatabaseTasks
                def drop
                  establish_master_connection
                  connection.select_all "select pg_terminate_backend(pg_stat_activity.pid) from pg_stat_activity where datname='#{configuration['database']}' AND state='idle';"
                  connection.drop_database configuration['database']
                end
              end
            end
          end
          

          (来自:http://www.krautcomputing.com/blog/2014/01/10/how-to-drop-your-postgres-database-with-rails-4/

          【讨论】:

            【解决方案13】:

            在生产环境中使用 Rails 5.2 应用程序和 PostgreSQL 数据库时,我遇到了同样的问题。

            我是这样解决的

            首先,注销PGAdmin 客户端上与数据库服务器的所有连接(如果有)。

            从终端停止使用数据库的每个会话。

            sudo kill -9 `ps -u postgres -o pid=`
            

            启动 PostgreSQL 服务器,因为上面的 kill 操作停止了 PostgreSQL 服务器。

            sudo systemctl start postgresql
            

            在生产环境中删除数据库并附加生产参数。

            rails db:drop RAILS_ENV=production DISABLE_DATABASE_ENVIRONMENT_CHECK=1
            

            就是这样。

            我希望这会有所帮助

            【讨论】:

              【解决方案14】:

              只需确保您已在任何打开的终端窗口中退出 rails 控制台并退出 rails 服务器...这是人们最常犯的错误之一

              【讨论】:

                【解决方案15】:

                我有一个类似的错误,说 1 个用户正在使用数据库,我意识到是我!我关闭了我的 Rails 服务器,然后执行了 rake:drop 命令,它成功了!

                【讨论】:

                  【解决方案16】:

                  重启服务器或电脑后,请重试。

                  这可能是一个简单的解决方案。

                  【讨论】:

                    【解决方案17】:

                    解决方案

                    Bash 脚本

                    ENV=development
                    
                    # restart postgresql
                    brew services restart postgresql
                    
                    # get name of the db from rails app
                    RAILS_CONSOLE_COMMAND="bundle exec rails c -e $ENV"
                    DB_NAME=$(echo 'ActiveRecord::Base.connection_config[:database]' | $RAILS_CONSOLE_COMMAND | tail -2 | tr -d '\"')
                    
                    # delete all connections to $DB_NAME
                    for pid in $(ps -ef | grep $DB_NAME | awk {'print$2'})
                    do
                       kill -9 $pid
                    done
                    
                    # drop db
                    DISABLE_DATABASE_ENVIRONMENT_CHECK=1 RAILS_ENV=$ENV bundle exec rails db:drop:_unsafe
                    

                    【讨论】:

                      【解决方案18】:

                      [OSX][开发/测试] 当你有很多 PostgreSQL 进程(如检查点、autovacuum 启动器等)时,有时很难确定正确的 PID。在这种情况下,你可以简单地运行:

                      brew services restart postgresql@12
                      

                      【讨论】:

                        猜你喜欢
                        • 2018-08-20
                        • 2012-10-07
                        • 1970-01-01
                        • 2022-06-16
                        • 2014-10-24
                        • 2012-02-15
                        • 2017-12-01
                        • 2012-12-31
                        • 1970-01-01
                        相关资源
                        最近更新 更多